home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / FWiX / FWiXApp / FWiXcopy.c < prev    next >
Encoding:
Text File  |  1999-05-17  |  82.4 KB  |  3,229 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWiXcopy.c
  3.  
  4.     Contains:    Software to handle file copies over FireWire.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.  
  10.     Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (jkl)    Jay Lloyd
  23.  
  24.     Change History (most recent first):
  25.  
  26.       <FW30>     6/19/97    jkl        Changed receive notification to let the application handle the
  27.                                     dialog and sound instead of notification manager. This allows
  28.                                     for background processing while notification alert is displayed
  29.                                     and makes playing the sound more reliable. Added a check at the
  30.                                     end of HandleReceiveComplete to see if there are any pending
  31.                                     send items from a send AppleScript command.
  32.       <FW29>      6/6/97    jkl        Nothing.
  33.       <FW28>     5/28/97    jkl        Changed timeout value on receive complete to account for slower
  34.                                     floppy copies.
  35.       <FW27>     5/27/97    jkl        Accounted for 4 byte index at the start of each control packet.
  36.                                     Changed received data handling to post the packet on the
  37.                                     received data queue along with the error. Changed handle receive
  38.                                     to make sure data packets get requeued on error. Made sure
  39.                                     progress dialog updates when only one item is being transferred.
  40.       <FW26>     5/16/97    jkl        Corrected dialog drawing routine to not try to draw a sending
  41.                                     item name if no item is being sent.
  42.       <FW25>     5/15/97    jkl        Modified error handling routines to handle errors during the
  43.                                     transfer setup routines. Added error handling for a driver
  44.                                     checksum routine.
  45.       <FW24>      5/7/97    jkl        Modified list structures to double linked lists to simplify
  46.                                     insertion and deletion of items. Fixed an uninitialized variable
  47.                                     in CheckItem. Fixed an index iterator in DirectoryBusy to make
  48.                                     sure each item in the directory is checked. Set status flags
  49.                                     before calling PrimeFork to prevent a case where the write
  50.                                     completion would return before all of the status flags were set.
  51.       <FW23>     4/29/97    jkl        Cleaned up alerts to use global alert with filter event
  52.                                     handling. Corrected check for file or file in folder busy in
  53.                                     HandleCheckItem. Moved OpenDropFolder before notification
  54.                                     posting in receive complete. Removed the code to zero an item's
  55.                                     finder location, this was causing all of the items to be lined
  56.                                     up on each other.
  57.       <FW22>      4/8/97    jkl        Cleared finder location information in the catinfo record before
  58.                                     calling SetCatInfo for received items. Changed my initials.
  59.       <FW21>     3/18/97    jkl        Corrected a problem with device removal and quitting where if
  60.                                     the last device in the list is getting removed, the previous
  61.                                     devices next pointer did not get nilled.
  62.       <FW20>     2/28/97    jkl        Changed string length from 5 to 15 in HandleReceiveComplete to
  63.                                     ensure string is long enough to display fork length and count.
  64.       <FW19>     2/27/97    jkl        Moved file conflict preferences to receiver control. Changed
  65.                                     HandleReceive to continue handling packets if an error occurs
  66.                                     but to only act on them if there is no error. Changed
  67.                                     ReceiveComplete to send error code and fork length expected vs.
  68.                                     fork length received. Removed receive timeout value since fwix
  69.                                     works as a cooperative task, timing out on receive may not mean
  70.                                     communication has failed, tie communications failure to control
  71.                                     packets out of order.
  72.       <FW18>     2/21/97    jkl        Added AdjustNodeIcons for mulitple node management in the sender
  73.                                     window.
  74.       <FW17>     2/19/97    jkl        Moved SendFileInfo to start of file transfer. Fixed a problem
  75.                                     with calculating size of and deleting directories. Changed the
  76.                                     node information exchange protocol to a request and reply. Fixed
  77.                                     a problem with the item precheck getting out of order. Fixed a
  78.                                     problem with mulitple files being sent out of order. Added
  79.                                     folders to the count of items to be sent. Corrected a problem
  80.                                     with received packets fields being cleared by file system calls.
  81.                                     Added the name of the item in the same name alert. Made the
  82.                                     replace option the default in the same name alert. Corrected a
  83.                                     problem with the receive folder being located on a volume other
  84.                                     than the boot volume.
  85.       <FW16>     2/14/97    jkl        Corrected a problem with sending items that are not on the
  86.                                     default volume.
  87.       <FW15>     2/13/97    jkl        Extended communication failure timeout values. During
  88.                                     simultaneous file transfers or starting to send a large number
  89.                                     of items, communications could stall long enough to make the
  90.                                     timers incorrectly go off.
  91.       <FW14>     2/13/97    jkl        Added ForkWriteComplete flag to FWWrite complete routine to make
  92.                                     sure a data buffer will be available to start reading next file
  93.                                     fork. Changed FSClose calls to PBClose. Fixed queueing problem
  94.                                     in HandleReceive.
  95.       <FW13>     2/11/97    jkl        Added support for read control and data packets. Read data
  96.                                     packets are passed to asynch file write routine.
  97.       <FW12>     2/10/97    ES        Cleaned up deallocation code.
  98.       <FW11>      2/2/97    jkl        Modified send check and receive check routines to use control
  99.                                     queue. Modified communications timeout values to allow receiver
  100.                                     more time to respond to sent items. Corrected timeout errors
  101.                                     during receive that were invalid by making sure a receive is in
  102.                                     progress. Corrected menu enabled/disabled states.
  103.       <FW10>     1/29/97    ES        Changed HandleFileReadComplete and HandleFileWriteComplete to
  104.                                     return noErr to work around bug in the File Manager.
  105.        <FW9>     1/27/97    ES        Added FW control PB queue so that start/end folder/fork, etc.
  106.                                     commands aren't queued with fork data packets. This fixes a case
  107.                                     where we'd run out of PBs for control commands which would halt
  108.                                     transmission.
  109.        <FW8>     1/27/97    jkl        Added timer routines to check for a file transfer communications
  110.                                     break. Added sendflags to handle item exists preferences. Added
  111.                                     a send precheck to get status of receive end. Added unique
  112.                                     file/folder name creation. Handled deleting folders properly by
  113.                                     removing all folder contents first.
  114.        <FW7>     1/16/97    jkl        Added user interface features for alpha candidate. Added file
  115.                                     receive notification. Changed node info packet handling to
  116.                                     display node icon.
  117.        <FW6>      1/8/97    ES        Changed to use FWX nodes instead of FWX drivers.
  118.        <FW5>    11/13/96    jkl        Multiple machine support. Node names. Transfer stop. CallDriver
  119.                                     interface instead of DoDriverIO.
  120.         <FW5>    11/7/96        jkl        Fixed folder copies. Added multiple machine support.
  121.                                     Added stop transfer functionality. Added receive node
  122.                                     name support.
  123.         <FW4>    11/5/96        ES        Fixed dequeue reentrancy bug.
  124.         <FW3>    10/31/96    jkl        Added support for sending/receiving multiple files/
  125.                                     folders. Cleaned up copy progress dialog.
  126.         <FW2>    10/16/96    jkl        For sending a file:
  127.                                        Modified queue handling to use OS Utils interrupt
  128.                                        safe queue routines. Broke the send file and
  129.                                     handle fork read complete routines into smaller
  130.                                     subroutines. Each subroutine and completion routine
  131.                                     makes their own calls to the file system and firewire
  132.                                     driver instead of queueing the requests to be sent
  133.                                     later. The ioMisc field of the parameter block
  134.                                     holds the packet type.
  135.                                     For receiving:
  136.                                     The FireWire read completion routine only queues
  137.                                     the data for later processing. It does not make
  138.                                     another read. All of the available read parameter
  139.                                     blocks are already on the driver read queue. The
  140.                                     read parameter blocks are queued for another read
  141.                                     after they are handled in the received data routine.
  142.                                     Broke the receive routine into smaller subroutines.
  143.                                     The ioMisc field of the parameter block holds the
  144.                                     packet type. If a file already exists in the drop folder
  145.                                     it is now just overwritten -- easier testing.
  146.         <FW1>    10/2/96        jkl        initial check-in
  147.  
  148. */
  149.  
  150. #include <Files.h>
  151. #include <Folders.h>
  152. #include <Errors.h>
  153. #include <Dialogs.h>
  154. #include <Script.h>
  155. #include <Devices.h>
  156. #include <Timer.h>
  157. #include <TextUtils.h>
  158. #include <Resources.h>
  159. #include <Sound.h>
  160.  
  161. #include "FWiX.h"
  162. #include "FWiXmain.h"
  163. #include "FWiXdrag.h"
  164.  
  165. #include <stdio.h>
  166. extern char  debugStr[256];
  167. static pascal void FWDebugStr(
  168.     ConstStr255Param            debuggerMsg)
  169. {
  170. #ifdef FW_DEBUG_BUILD
  171. #if FW_DEBUG_BUILD
  172.     DebugStr (debuggerMsg);
  173. #endif
  174. #endif
  175. }
  176.  
  177. //////////////////////////////////////////////////////////////////////////////
  178. //
  179. // Internal procedure prototypes.
  180. //
  181.  
  182. OSErr HandleFSItem (
  183.     FSSpecPtr            pFSItem,
  184.     FWXNodeID            recvNodeID);
  185.     
  186. static OSErr SendTxCheck(
  187.     FWXNodeID            recvNodeID,
  188.     NodeSendItemPtr        pSendItem);
  189.  
  190. OSErr SendFSItem (
  191.     FSSpecPtr            pFSItem,
  192.     FWXNodeID            recvNodeID,
  193.     Boolean                startSend);
  194.     
  195. static OSErr SendAFolder(
  196.     FSSpecPtr            pFSItem,
  197.     FWXNodeID            recvNodeID);
  198.     
  199. static OSErr QueueFolderItems(
  200.     FSSpecPtr            pFolderSpec,
  201.     FWXNodeID            recvNodeID);
  202.  
  203. static OSErr SendFolderInfo(
  204.     FSSpecPtr                pFSItem);
  205.  
  206. static OSErr SendAFile (
  207.     FSSpecPtr            pFSItem,
  208.     FWXNodeID            recvNodeID);
  209.     
  210. static OSErr SendStartFolder (
  211.     ConstStr255Param    pFileName);
  212.  
  213. static OSErr SendFileInfo (
  214.     CInfoPBPtr            pCatInfo);
  215.  
  216. static OSErr SendEndFolder (void);
  217.  
  218. static OSErr SendStartFile (
  219.     ConstStr255Param    pFileName);
  220.  
  221. static OSErr SendStartFork(
  222.     UInt32                length,
  223.     UInt32                whichFork);
  224.  
  225. static OSErr PrimeAFork (
  226.     SInt16                forkRefNum);
  227.     
  228. static OSErr SendEndFork(
  229.     UInt32                whichFork);
  230.     
  231. void HandleForkReadComplete (void);
  232.  
  233. static OSErr FinishSendFile (void);
  234.  
  235. void HandleReceive (void);
  236.  
  237. static OSErr HandleReceiveComplete(
  238.     FWXNodeID                recvNode,
  239.     UInt32                    result,
  240.     UInt32                    forkLength,
  241.     UInt32                    lengthRecvd);
  242.  
  243. static OSErr HandlePreflightReply(
  244.     FWXNodeID                sendingNodeID,
  245.     SInt32                    itemSize,
  246.     ConstStr255Param        itemName);
  247.  
  248. static Boolean DirectoryBusy (
  249.     SInt32                    dirID);
  250.  
  251. static OSErr HandleCheckItem(
  252.     CurFileInfoPtr            pCurFileInfo,
  253.     FWXNodeID                sendingNodeID,
  254.     UInt32                    itemSize,
  255.     ConstStr255Param        itemName);
  256.  
  257. static OSErr SendReceiveComplete(
  258.     OSErr                    sendError,
  259.     FWXNodeID                senderID,
  260.     UInt32                    forkLegnth,
  261.     UInt32                    recvCount,
  262.     ConstStr255Param        itemName);
  263.     
  264. static OSErr HandleStartFolder(
  265.     ConstStr255Param    folderName,
  266.     SInt32                *curDirID);
  267.  
  268. static OSErr CreateUniqueFolder(
  269.     ConstStr255Param    fileName,
  270.     FSSpecPtr            pFileSpec,
  271.     SInt32                *dirID);
  272.  
  273. static OSErr DeleteDirectoryContents (
  274.     SInt32                dirID);
  275.     
  276. static OSErr DeleteDirectory (
  277.     FSSpecPtr            pDirSpec);
  278.     
  279. static OSErr DeleteFile(
  280.     SInt16                vRefNum,
  281.     SInt32                dirID,
  282.     StringPtr            fName);
  283.  
  284. static OSErr HandleStartFile(
  285.     ConstStr255Param    fileName,
  286.     CurFileInfoPtr        pCurFileInfo);
  287.  
  288. static OSErr CreateUniqueFile(
  289.     ConstStr255Param    fileName,
  290.     FSSpecPtr            pFileSpec,
  291.     SInt32                dirID);
  292.  
  293. static OSErr HandleStartFork(
  294.     IOParamPtr            pb,
  295.     UInt32                forkLength,
  296.     SInt16                refNum);
  297.     
  298. static OSErr HandleForkData(
  299.     IOParamPtr            pb,
  300.     SInt16                refNum);
  301.  
  302. OSErr HandleStopTransfer(
  303.     CurFileInfoPtr        pCurFileInfo);
  304.  
  305. static OSErr HandleEndFolder(
  306.     SInt32                *curDirID);
  307.  
  308. static OSErr HandleNodeInfoRequest(
  309.     ConstStr255Param        nodeName,
  310.     FWXNodeID                nodeID);
  311.  
  312. static OSErr HandleNodeInfoReply(
  313.     ConstStr255Param        nodeName,
  314.     FWXNodeID                nodeID);
  315.  
  316. static void CleanupTxError(
  317.     RecvNodePtr                pNode);
  318.  
  319. static OSErr HandleNodeQuit(
  320.     FWXNodeID                nodeID);
  321.  
  322. static OSErr HandleFolderInfo(
  323.     CInfoPBPtr            pCatInfoPB,
  324.     SInt32                curDirID);
  325.  
  326. static OSErr HandleFileInfo(
  327.     FSSpecPtr            pNewFileSpec,
  328.     CInfoPBPtr            pCatInfoPB);
  329.  
  330. static OSErr AddItemToQueue (
  331.     HFileInfo            *pFileInfo,
  332.     FSSpecPtr            pFSItem,
  333.     Boolean                isFile);
  334.     
  335. OSErr FSpGetCatInfo (
  336.     FSSpec                 *fsSpec,
  337.     CInfoPBPtr            result);
  338.     
  339. void CleanupCopyDialog(
  340.     WindowPtr            theDialog);
  341.     
  342. static OSErr DisplayCopyDialog (void);
  343.     
  344. pascal void DrawProgressBar(
  345.     WindowPtr            theWindow,
  346.     SInt16                itemNo);
  347.     
  348. void UpdateProgressBar(
  349.     WindowPtr            theWindow,
  350.     SInt16                itemNo);
  351.     
  352. static OSErr CalcDirectorySize (
  353.     SInt32                dirID,
  354.     SInt16                vRefNum,
  355.     UInt32                *dirSize,
  356.     UInt32                *dirItems);
  357.  
  358. OSErr GetItemSize (
  359.     NodeSendItemPtr        pSendItem);
  360.  
  361. OSErr CountCopyData (
  362.     FSSpec                 *pFSSpec);
  363.  
  364.     
  365. //////////////////////////////////////////////////////////////////////////////
  366. //
  367. //    External procedure prototypes
  368. //
  369.     
  370. extern OSErr GetNodeInfo (
  371.     FWXNodeID                nodeID,
  372.     RecvNodePtr                *pRecvNode);
  373.  
  374. extern OSErr SendFWXInfo (
  375.     FWXNodeID                nodeID,
  376.     UInt32                    sendType);
  377.  
  378. extern OSErr InitRecvNode (
  379.     FWXNodeID                nodeID,
  380.     ConstStr255Param        nodeName);
  381.  
  382. extern void OpenDropFolder (void);
  383.  
  384. extern pascal void HandleReplyTimeout (
  385.     MyTMTaskPtr            pTMTask);
  386.  
  387. extern void AdjustNodeIcons (
  388.     WindowDataPtr            pWinData,
  389.     Rect                    *windRect);
  390.  
  391. extern OSErr AdjustScrollBars (
  392.     WindowPtr                pWin,
  393.     Boolean                    adjustSizes);
  394.  
  395. extern void StopTransfer (
  396.     RecvNodePtr                pNode);
  397.     
  398. //////////////////////////////////////////////////////////////////////////////
  399. //
  400. //    Globals
  401. //
  402. UInt32                        gBytesToCopy;
  403. UInt32                        gBytesCopied;
  404. UInt32                        gItemsToCopy;
  405. CInfoPBRec                    gCatInfoPB;            // used in directory traversal to help recursion
  406.  
  407. extern FWXAppDataPtr        gpFWXAppData;
  408. extern QHdr                    gSendQHdr;
  409. extern QHdr                    gAESendQHdr;
  410. extern QHdr                    gReceiveQHdr;
  411. extern QHdr                    gFileReadQHdr;
  412. extern QHdr                    gFWControlQHdr;
  413. extern QHdr                    gCurFileQHdr;
  414. extern SInt16                gCurForkRefNum;
  415.  
  416.  
  417. extern Boolean                gSendingFile,
  418.                             gCheckingTransfer,
  419.                             gSendingDataFork,
  420.                             gSendingResFork,
  421.                             gForkWriteComplete,
  422.                             gForkComplete;
  423.  
  424. extern FWXNodeID            gReceiveError;
  425.  
  426. //////////////////////////////////////////////////////////////////////////////
  427. //
  428. //    HandleFSItem
  429. //
  430. //    Called for each item dropped on a node icon. There will be two lists, one
  431. //    for items that need to be checked if ok to send (size, name, etc.) and the
  432. //    other for items waiting to be sent.
  433. //
  434. //    Add the item to the receive node's checking for ok to transfer list and see
  435. //    if the receive node can handle this item.
  436. //
  437. OSErr HandleFSItem (
  438.     FSSpecPtr            pFSItem,
  439.     FWXNodeID            recvNodeID)
  440. {
  441.     RecvNodePtr                pRecvNode;
  442.     NodeSendItemPtr            pCheckItem;
  443.     NodeSendItemPtr            pTempCheckItem;
  444.     OSErr                    err;
  445.     
  446.     if (gpFWXAppData->pSenderWindow == FrontWindow())
  447.     {
  448.         DisplayCopyDialog();
  449.         gCheckingTransfer = true;
  450.     }
  451.         
  452.     // get a pointer to the node record
  453.     err = GetNodeInfo(recvNodeID, &pRecvNode);
  454.     if (err == noErr)
  455.     {
  456.         // add the item to the node's send list
  457.         pCheckItem = (NodeSendItemPtr) NewPtrClear(sizeof(NodeSendItem));
  458.         if (pCheckItem == nil)
  459.             return memFullErr;
  460.         pCheckItem->sendItemSpec = *pFSItem;
  461.  
  462.         if (pRecvNode->pTxItemList == nil)
  463.         {
  464.             // first item in the list
  465.             pRecvNode->pTxItemList = pCheckItem;
  466.         }
  467.         else
  468.         {
  469.             // traverse the list and add this item to the end
  470.             pTempCheckItem = pRecvNode->pTxItemList;
  471.             while (pTempCheckItem->pNextSendItem != nil)
  472.             {
  473.                 pTempCheckItem = pTempCheckItem->pNextSendItem;
  474.             }
  475.             pTempCheckItem->pNextSendItem = pCheckItem;
  476.             pCheckItem->pPreviousSendItem = pTempCheckItem;
  477.         }
  478.         // JKL *** need to put a timer on this call to cancel send if no response.
  479.         err = SendTxCheck(recvNodeID, pCheckItem);
  480.     }
  481.     return err;    
  482. }
  483.  
  484. ////////////////////////////////////////////////////////////////////////////////
  485. //
  486. //    SendTxCheck
  487. //
  488. //    Send a packet with item name and size to receive node for a check
  489. //    of item exists and space ok.
  490. //
  491. static OSErr SendTxCheck(
  492.     FWXNodeID            recvNodeID,
  493.     NodeSendItemPtr        pCheckItem)
  494. {
  495.     IOParamPtr            pIOPb;
  496.     FWXPacketPtr        pPktInfo;
  497.     OSErr                err = noErr;
  498.  
  499.     err = GetItemSize(pCheckItem);
  500.     if (err != noErr)
  501.     {
  502.         sprintf(debugStr, "SendTxCheck, error in GetItemSize: %d", err);
  503.         FWDebugStr((ConstStr255Param) c2pstr (debugStr));
  504.     }
  505.  
  506.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  507.     if (pIOPb != nil)
  508.     {
  509.         SetupFWControlPB(pIOPb);
  510.         // SetupFWControlPB will leave an invalid node id in nameptr at this point
  511.         pIOPb->ioNamePtr = (StringPtr) recvNodeID;
  512.         
  513.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  514.         pPktInfo->packetType = kPreflightCopy;
  515.         pIOPb->ioMisc = (Ptr) kPreflightCopy;
  516.         pPktInfo->packetData = (Ptr) pCheckItem->itemSize;
  517.  
  518.         BlockMove(pCheckItem->sendItemSpec.name, ((Ptr) &pPktInfo->packetData) + 4,
  519.                   pCheckItem->sendItemSpec.name[0] + 1);
  520.         pIOPb->ioReqCount = pCheckItem->sendItemSpec.name[0] + 1 + 4 + 4;    // length of string plus packet header plus size
  521.         
  522.         err = CallFWXNode(pIOPb);
  523.     }
  524.     else
  525.     {
  526.         err = qErr;
  527.         FWDebugStr("\pNo buffer for SendTxCheck");
  528.     }
  529.     return err;
  530. }    
  531.  
  532. //////////////////////////////////////////////////////////////////////////////
  533. //
  534. //    SendFSItem
  535. //
  536. //    Called for each item dropped on a node icon once the item has been
  537. //    OK'd to send. Add the item to the transfer queue. If there is no
  538. //    transfer under way and all pending items are on the send queue, start sending.
  539. //
  540. OSErr SendFSItem (
  541.     FSSpecPtr            pFSItem,            // the file or folder to add to the queue
  542.     FWXNodeID            recvNodeID,            // the receiver's id
  543.     Boolean                readyToSend)        // true when all pending items are on the queue
  544. {
  545.     GrafPtr                curPort;
  546.     DialogPtr            pDialog;
  547.     CInfoPBRec            catInfoPB;
  548.     TxFSSpecPtr            pTxItem;
  549.     Handle                hItem;
  550.     Rect                r;
  551.     SInt16                itemType;
  552.     OSErr                err;
  553.     Boolean                isFile;
  554.     
  555.     err = CountCopyData(pFSItem);
  556.     if (err != noErr)
  557.     {
  558.         sprintf(debugStr, "SendFSItem, error in CountCopyData: %d", err);
  559.         FWDebugStr((ConstStr255Param) c2pstr (debugStr));
  560.     }
  561.     err = FSpGetCatInfo(pFSItem, &catInfoPB);
  562.     if (err == noErr)
  563.     {
  564.         isFile = !(catInfoPB.dirInfo.ioFlAttrib & ioDirMask);
  565.  
  566.         pTxItem = (TxFSSpecPtr) NewPtr(sizeof(TxFSSpec));
  567.         if (pTxItem != nil)
  568.         {
  569.             pTxItem->recvNode = recvNodeID;
  570.             pTxItem->pFSSpec = (FSSpecPtr) NewPtr(sizeof(FSSpec));
  571.             if (pTxItem->pFSSpec != nil)
  572.             {
  573.                 *(pTxItem->pFSSpec) = *pFSItem;
  574.                 if (isFile)
  575.                     pTxItem->itemType = kFileInfo;
  576.                 else
  577.                     pTxItem->itemType = kStartFolder;
  578.                 Enqueue((QElemPtr) pTxItem, &gSendQHdr);
  579.  
  580.             } else err = memFullErr;
  581.         } else err = memFullErr;
  582.  
  583.         if ((err == noErr) && !gSendingFile && readyToSend)
  584.         {
  585.             gCheckingTransfer = false;
  586.             gSendingFile = true;
  587.             gBytesCopied = 0;
  588.             pDialog = FrontWindow();
  589.             GetDialogItem(pDialog, kProgressPrompt, &itemType, &hItem, &r);
  590.             SetDialogItemText(hItem, "\pSending: ");
  591.             
  592.             // force dialog update
  593.             GetPort(&curPort);
  594.             SetPort(pDialog);
  595.             InvalRect(&pDialog->portRect);
  596.             SetPort(curPort);
  597.             
  598.  
  599.             pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  600.             if (pTxItem != nil)
  601.             {
  602.                 if (pTxItem->itemType == kFileInfo)
  603.                     SendAFile(pTxItem->pFSSpec, pTxItem->recvNode);
  604.                 else if (pTxItem->itemType == kStartFolder)
  605.                     SendAFolder(pTxItem->pFSSpec, pTxItem->recvNode);
  606.             }
  607.         }
  608.     }
  609.     return err;
  610. }    
  611.  
  612. //////////////////////////////////////////////////////////////////////////////
  613. //
  614. //    SendAFolder
  615. //
  616. //    Handle sending a folder. Add each item in the folder to the transfer
  617. //    queue and an end folder item. Send the folder info. Send each item in
  618. //    the folder.
  619. //
  620. static OSErr SendAFolder(
  621.     FSSpecPtr                pFSItem,
  622.     FWXNodeID                recvNodeID)
  623. {
  624.     QElemPtr                restOfQueue;
  625.     QElemPtr                curQTail;
  626.     TxFSSpecPtr                pTxItem;
  627.     OSErr                    err;
  628.     
  629.     // save a pointer to the rest of the queue
  630.     // the rest of the queue is reattached after the folders' items
  631.     restOfQueue = gSendQHdr.qHead->qLink;
  632.     gSendQHdr.qHead->qLink = nil;
  633.     curQTail = gSendQHdr.qTail;
  634.     
  635.     // handle special case of only one item in queue
  636.     if (curQTail == gSendQHdr.qHead)
  637.         curQTail = nil;
  638.     gSendQHdr.qTail = gSendQHdr.qHead;
  639.     
  640.     err = QueueFolderItems(pFSItem, recvNodeID);
  641.     
  642.     // add end folder queue element
  643.     pTxItem = (TxFSSpecPtr) NewPtr(sizeof(TxFSSpec));
  644.     if (pTxItem != nil)
  645.     {
  646.         pTxItem->itemType = kEndFolder;
  647.         pTxItem->recvNode = recvNodeID;
  648.         Enqueue((QElemPtr) pTxItem, &gSendQHdr);
  649.     }
  650.     else
  651.         err = memFullErr;
  652.     
  653.     gSendQHdr.qTail->qLink = restOfQueue;
  654.     if (curQTail != nil)
  655.         gSendQHdr.qTail = curQTail;
  656.     
  657.     SendStartFolder(pFSItem->name);
  658.     SendFolderInfo(pFSItem);
  659.     
  660.     // dequeue and dispose of folder queue entry
  661.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  662.     Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  663.     DisposePtr((Ptr) pTxItem->pFSSpec);
  664.     DisposePtr((Ptr) pTxItem);
  665.  
  666.     // get another queue item
  667.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  668.     if (pTxItem != nil) {
  669.         if (pTxItem->itemType == kFileInfo)
  670.             SendAFile(pTxItem->pFSSpec, pTxItem->recvNode);
  671.         else if (pTxItem->itemType == kStartFolder)
  672.             SendAFolder(pTxItem->pFSSpec, pTxItem->recvNode);
  673.         else if (pTxItem->itemType == kEndFolder)
  674.             SendEndFolder();
  675.  
  676.     } else {
  677.         gSendingFile = false;
  678.  
  679.         // toss the progress bar
  680.         CleanupCopyDialog(FrontWindow());
  681.     }
  682.     
  683.     return err;
  684. }
  685.  
  686.  
  687. //////////////////////////////////////////////////////////////////////////////
  688. //
  689. //    QueueFolderItems
  690. //
  691. //    Traverse a folder, adding each of its items to the transmit queue.
  692. //
  693. static OSErr QueueFolderItems(
  694.     FSSpecPtr                pFolderSpec,
  695.     FWXNodeID                recvNodeID)
  696. {
  697.     TxFSSpecPtr                pTxItem;
  698.     CInfoPBRec                catInfoPB;
  699.     Str63                    fileNameBuffer;
  700.     UInt32                    dirID;
  701.     SInt16                    index;
  702.     OSErr                    err = noErr;
  703.     Boolean                    isFile;
  704.  
  705.     err = FSpGetCatInfo(pFolderSpec, &catInfoPB);
  706.     catInfoPB.hFileInfo.ioNamePtr = fileNameBuffer;
  707.  
  708.     if (err == noErr)
  709.     {
  710.         dirID = catInfoPB.dirInfo.ioDrDirID;
  711.  
  712.         for (index = 1; ; index++)
  713.         {
  714.             // reset the directory id after each call to PBGetCatInfo
  715.             catInfoPB.hFileInfo.ioDirID = dirID;
  716.             catInfoPB.hFileInfo.ioFDirIndex = index;
  717.             
  718.             err = PBGetCatInfoSync(&catInfoPB);
  719.             if (err)
  720.             {
  721.                 // returns file not found when directory has been traversed
  722.                 if (err == fnfErr)
  723.                     err = noErr;
  724.                 break;
  725.             }
  726.                 
  727.             isFile = !(catInfoPB.dirInfo.ioFlAttrib & ioDirMask);
  728.             
  729.             // create queue entry
  730.             pTxItem = (TxFSSpecPtr) NewPtr(sizeof(TxFSSpec));
  731.             if (pTxItem == nil)
  732.             {
  733.                 err = memFullErr;
  734.                 break;
  735.             }
  736.             
  737.             // create fsspec for queue entry
  738.             pTxItem->pFSSpec = (FSSpecPtr) NewPtr(sizeof(FSSpec));
  739.             if (pTxItem->pFSSpec == nil)
  740.             {
  741.                 err = memFullErr;
  742.                 break;
  743.             }
  744.             
  745.             // fill in fsspec fields
  746.             pTxItem->pFSSpec->vRefNum = pFolderSpec->vRefNum;
  747.             pTxItem->pFSSpec->parID = dirID;
  748.             BlockMove(fileNameBuffer,pTxItem->pFSSpec->name,fileNameBuffer[0]+1);
  749.             
  750.             // fill in other queue element fields
  751.             pTxItem->recvNode = recvNodeID;
  752.             if (isFile)
  753.                 pTxItem->itemType = kFileInfo;
  754.             else
  755.                 pTxItem->itemType = kStartFolder;
  756.             Enqueue((QElemPtr) pTxItem, &gSendQHdr);
  757.         }
  758.     }
  759.     
  760.     return err;
  761. }
  762.  
  763.  
  764. //////////////////////////////////////////////////////////////////////////////
  765. //
  766. //    SendAFile
  767. //
  768. //    Start sending a file to another firewire node. Send start file
  769. //  packet with the file name, send start data fork packet with
  770. //    fork size. If there is no data fork, send start resource packet
  771. //    with fork size. Prime the send fork routine. The rest of the file
  772. //    send will complete as the PBRead of the file forks completes.
  773. //
  774. static OSErr SendAFile(
  775.     FSSpecPtr                pFSItem,
  776.     FWXNodeID                recvNodeID)
  777. {
  778.     CInfoPBRec                catInfoPB;
  779.     UInt32                    forkLength;
  780.     OSErr                    err;
  781.     
  782.     err = FSpGetCatInfo(pFSItem, &catInfoPB);
  783.     if (err == noErr)
  784.         err = SendStartFile((ConstStr255Param) pFSItem->name);
  785.  
  786.     if (err == noErr)
  787.         err = SendFileInfo(&catInfoPB);
  788.  
  789.     if (err == noErr)
  790.     {
  791.         forkLength = catInfoPB.hFileInfo.ioFlLgLen;        
  792.         if (forkLength != 0)
  793.         {
  794.             err = SendStartFork(forkLength, kStartDataFork);
  795.             if (err == noErr)
  796.             {
  797.                 err = FSpOpenDF(pFSItem, fsRdPerm, &gCurForkRefNum);
  798.                 if (err == noErr)
  799.                 {
  800.                     gSendingDataFork = true;
  801.                     gForkComplete = false;
  802.                     gForkWriteComplete = false;
  803.                     err = PrimeAFork(gCurForkRefNum);
  804.                     if (err != noErr)
  805.                     {
  806.                         gSendingDataFork = false;
  807.                         gForkComplete = true;
  808.                         gForkWriteComplete = true;
  809.                     }
  810.                 }
  811.             }
  812.         }
  813.         else
  814.         {
  815.             // data fork empty, start sending resource fork
  816.             forkLength = catInfoPB.hFileInfo.ioFlRLgLen;
  817.             if (forkLength != 0)
  818.             {
  819.                 err = SendStartFork(forkLength, kStartResFork);
  820.                 if (err == noErr)
  821.                 {
  822.                     err = FSpOpenRF(pFSItem, fsRdPerm, &gCurForkRefNum);
  823.                     if (err == noErr)
  824.                     {
  825.                         gSendingResFork = true;
  826.                         gForkComplete = false;
  827.                         gForkWriteComplete = false;
  828.                         err = PrimeAFork(gCurForkRefNum);
  829.                         if (err != noErr)
  830.                         {
  831.                             gSendingResFork = false;
  832.                             gForkComplete = true;
  833.                             gForkWriteComplete = true;
  834.                         }
  835.                     }
  836.                 }
  837.             }
  838.             else
  839.             {
  840.                 // no data in the file at all
  841.                 err = FinishSendFile();
  842.             }
  843.         }
  844.     }
  845.     return err;
  846. }
  847.  
  848. //////////////////////////////////////////////////////////////////////////////
  849. //
  850. //    SendStartFolder
  851. //
  852. //    Send the start folder packet with the folder name
  853. //
  854. static OSErr SendStartFolder(
  855.     ConstStr255Param            pFolderName)
  856. {
  857.     FWXPacketPtr                pPktInfo;                // points to ioBuffer
  858.     IOParamPtr                    pIOPb;                    // a parameter block for reading
  859.     OSErr                        err = noErr;
  860.  
  861.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  862.     if (pIOPb != nil) {
  863.         SetupFWControlPB(pIOPb);
  864.         
  865.         // copy the file name into the data buffer for start file packet                
  866.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  867.         pPktInfo->packetType = kStartFolder;
  868.         pIOPb->ioMisc = (Ptr) kStartFolder;
  869.         BlockMove(pFolderName, &pPktInfo->packetData, pFolderName[0]+1);
  870.         pIOPb->ioReqCount = pFolderName[0] + 1 + 4;    // length of name plus packet header
  871.         
  872.         err = CallFWXNode(pIOPb);
  873.  
  874.     } else {
  875.         err = qErr;
  876.         FWDebugStr("\pNo buffer for start folder");
  877.     }
  878.     
  879.     return err;
  880. }
  881.  
  882. //////////////////////////////////////////////////////////////////////////////
  883. //
  884. //    SendEndFolder
  885. //
  886. //    Send end folder packet
  887. //
  888. static OSErr SendEndFolder(void)
  889. {
  890.     IOParamPtr                    pIOPb;            // a queue record
  891.     FWXPacketPtr                pPktInfo;
  892.     TxFSSpecPtr                    pTxItem;
  893.     OSErr                        err;
  894.  
  895.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  896.     if (pIOPb != nil) {
  897.         SetupFWControlPB(pIOPb);
  898.                             
  899.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  900.         pPktInfo->packetType = kEndFolder;
  901.         pIOPb->ioMisc = (Ptr) kEndFolder;
  902.         pIOPb->ioReqCount = 4;
  903.  
  904.         err = CallFWXNode(pIOPb);
  905.     
  906.     } else {
  907.         err = qErr;
  908.         FWDebugStr("\pNo buffer, SendEndFolder");
  909.     }
  910.  
  911.     // dequeue and dispose of end folder queue entry
  912.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  913.     Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  914.     DisposePtr((Ptr) pTxItem);
  915.     gItemsToCopy--;
  916.  
  917.     // get another queue item
  918.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  919.     if (pTxItem != nil) {
  920.         if (pTxItem->itemType == kFileInfo)
  921.             SendAFile(pTxItem->pFSSpec, pTxItem->recvNode);
  922.         else if (pTxItem->itemType == kStartFolder)
  923.             SendAFolder(pTxItem->pFSSpec, pTxItem->recvNode);
  924.         else if (pTxItem->itemType == kEndFolder)
  925.             SendEndFolder();
  926.  
  927.     } else {
  928.         gSendingFile = false;
  929.  
  930.         // toss the progress bar
  931.         CleanupCopyDialog(FrontWindow());
  932.     }
  933.  
  934.     return err;
  935. }
  936.  
  937. //////////////////////////////////////////////////////////////////////////////
  938. //
  939. //    SendFolderInfo
  940. //
  941. //    Send the folder catalog info
  942. //
  943. static OSErr SendFolderInfo(
  944.     FSSpecPtr                    pFSItem)
  945. {
  946.     IOParamPtr                    pIOPb;            // a queue record
  947.     FWXPacketPtr                pPktInfo;
  948.     OSErr                        err;
  949.     
  950.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  951.     if (pIOPb != nil)
  952.     {
  953.         SetupFWControlPB(pIOPb);
  954.                             
  955.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  956.         pPktInfo->packetType = kFolderInfo;
  957.         pIOPb->ioMisc = (Ptr) kFolderInfo;
  958.         pIOPb->ioReqCount = sizeof(CInfoPBRec) + 4;        // catalog info plus packet header
  959.     
  960.         err = FSpGetCatInfo(pFSItem, (CInfoPBPtr) &pPktInfo->packetData);
  961.         
  962.         if (err == noErr)
  963.             err = CallFWXNode(pIOPb);
  964.     }
  965.     else
  966.     {
  967.         err = qErr;
  968.         FWDebugStr("\pNo buffer, SendFolderInfo");
  969.     }
  970.     return err;
  971. }
  972.  
  973. //////////////////////////////////////////////////////////////////////////////
  974. //
  975. //    SendStartFile
  976. //
  977. //    Send the start file packet including the file name
  978. //
  979. static OSErr SendStartFile(
  980.     ConstStr255Param            pFileName)
  981. {
  982.     FWXPacketPtr                pPktInfo;                // points to ioBuffer
  983.     IOParamPtr                    pIOPb;                    // a parameter block for reading
  984.     OSErr                        err = noErr;
  985.  
  986.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  987.     if (pIOPb != nil) {
  988.         SetupFWControlPB(pIOPb);
  989.         
  990.         // copy the file name into the data buffer for start file packet                
  991.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  992.         pPktInfo->packetType = kStartFile;
  993.         pIOPb->ioMisc = (Ptr) kStartFile;
  994.         BlockMove(pFileName, (Ptr) &pPktInfo->packetData, pFileName[0]+1);
  995.         pIOPb->ioReqCount = pFileName[0] + 1 + 4;    // length of name plus packet header plus flags
  996.         
  997.         err = CallFWXNode(pIOPb);
  998.  
  999.     } else {
  1000.         err = qErr;
  1001.         FWDebugStr("\pNo buffer for start file");
  1002.     }
  1003.     
  1004.     return err;
  1005. }
  1006.  
  1007. //////////////////////////////////////////////////////////////////////////////
  1008. //
  1009. //    SendStartFork
  1010. //
  1011. //    Send a start fork packet including fork length
  1012. //
  1013. static OSErr SendStartFork(
  1014.     UInt32                    length,
  1015.     UInt32                    whichFork)
  1016. {
  1017.     FWXPacketPtr            pPktInfo;                // puts a packet structure on ioBuffer
  1018.     IOParamPtr                pIOPb;                    // a parameter block for writing
  1019.     OSErr                    err = noErr;
  1020.  
  1021.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  1022.     if (pIOPb != nil) {
  1023.         SetupFWControlPB(pIOPb);
  1024.                     
  1025.         // copy fork length into start fork packet    
  1026.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  1027.         pPktInfo->packetType = whichFork;
  1028.         pIOPb->ioMisc = (Ptr) whichFork;
  1029.         pPktInfo->packetData = (Ptr) length;
  1030.         pIOPb->ioReqCount = 4 + 4;            // packet header + fork length
  1031.  
  1032.         err = CallFWXNode(pIOPb);
  1033.         
  1034.     } else {
  1035.         err = qErr;
  1036.         FWDebugStr("\pNo buffer for start fork");
  1037.     }
  1038.     
  1039.     return err;
  1040. }
  1041.  
  1042. //////////////////////////////////////////////////////////////////////////////
  1043. //
  1044. //    PrimeAFork
  1045. //
  1046. //    Set up fork transfer, will be completed elsewhere.
  1047. //    This routine does not set the packet type. Have to do that in read
  1048. //    completion.
  1049. //
  1050. static OSErr PrimeAFork(
  1051.     SInt16                forkRefNum)
  1052. {
  1053.     IOParamPtr            pPB;                // IO parameter block
  1054.     OSErr                anErr = noErr;
  1055.     
  1056.     FWIXDequeue ((QElemPtr *) &pPB, &gFileReadQHdr);
  1057.     if (pPB != nil) {
  1058.         // set file pos to start
  1059.         pPB->ioRefNum = forkRefNum;
  1060.         pPB->ioPosMode = fsFromStart;
  1061.         pPB->ioPosOffset = 0;
  1062.         anErr = PBSetFPosSync((ParmBlkPtr) pPB);
  1063.         if (anErr != noErr)
  1064.             return anErr;
  1065.  
  1066.         // do the read
  1067.         SetupFileReadPB(pPB);
  1068.         anErr = PBReadAsync((ParmBlkPtr) pPB);
  1069.  
  1070.     } else {
  1071.         anErr = qErr;
  1072.         FWDebugStr("\pNo buffer for prime fork");
  1073.     }
  1074.     
  1075.     return anErr;
  1076. }
  1077.  
  1078. //////////////////////////////////////////////////////////////////////////////
  1079. //
  1080. //    SendEndFork
  1081. //
  1082. //    Send the end fork packet
  1083. //
  1084. static OSErr SendEndFork(
  1085.     UInt32                        whichFork)
  1086. {
  1087.     FWXPacketPtr                pPktInfo;        // puts a packet structure on ioBuffer
  1088.     IOParamPtr                    pIOPb;            // write parameter block
  1089.     OSErr                        err = noErr;
  1090.  
  1091.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  1092.     if (pIOPb != nil) {
  1093.         SetupFWControlPB(pIOPb);
  1094.                 
  1095.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  1096.         pPktInfo->packetType = whichFork;
  1097.         pIOPb->ioMisc = (Ptr) whichFork;
  1098.         pIOPb->ioReqCount = 4;                // just packet header
  1099.  
  1100.         err = CallFWXNode(pIOPb);
  1101.         
  1102.     } else {
  1103.         FWDebugStr("\pNo buffer for end fork");
  1104.         err = qErr;
  1105.     }
  1106.     
  1107.     return err;
  1108. }
  1109.  
  1110. //////////////////////////////////////////////////////////////////////////////
  1111. //
  1112. //    HandleFileReadComplete
  1113. //
  1114. //    Completion routine for PBRead from file. Send the read data to the firewire
  1115. //    node.
  1116. //
  1117. pascal OSErr HandleFileReadComplete(
  1118.     ParmBlkPtr            pFilePB)
  1119. {
  1120.     IOParamPtr            pb;                // parameter block to issue another read
  1121.     OSErr                ioResult;
  1122.     
  1123.     ioResult = pFilePB->ioParam.ioResult;
  1124.     
  1125.     if ((ioResult == noErr) || (ioResult == eofErr)) {
  1126.  
  1127.         if (ioResult == eofErr)
  1128.             gForkComplete = true;
  1129.             
  1130.         if (pFilePB->ioParam.ioActCount != 0)
  1131.         {
  1132.             // send the read packet to the FireWire node
  1133.             pFilePB->ioParam.ioMisc = (Ptr) kForkData;
  1134.             pFilePB->ioParam.ioReqCount = pFilePB->ioParam.ioActCount;
  1135.             gBytesCopied += pFilePB->ioParam.ioActCount;
  1136.             SetupFWWritePB((IOParamPtr) pFilePB);
  1137.  
  1138.             CallFWXNode((IOParamPtr) pFilePB);
  1139.         }
  1140.         else
  1141.         {
  1142.             // no data in the packet, just queue it back to the read quueue
  1143.             Enqueue((QElemPtr) pFilePB, &gFileReadQHdr);
  1144.         }
  1145.         
  1146.         if (ioResult == noErr)
  1147.         {
  1148.             // there is more data, do another read
  1149.             FWIXDequeue ((QElemPtr *) &pb, &gFileReadQHdr);
  1150.             if (pb != nil)
  1151.             {
  1152.                 SetupFileReadPB(pb);
  1153.                 PBReadAsync((ParmBlkPtr) pb);
  1154.             }
  1155.         }
  1156.     }
  1157.     else
  1158.     {
  1159.         sprintf(debugStr, "Error in PBRead from file: %hd", pFilePB->ioParam.ioResult);
  1160.         FWDebugStr((ConstStr255Param) c2pstr (debugStr));
  1161.         Enqueue((QElemPtr) pFilePB, &gFileReadQHdr);
  1162.     }
  1163.  
  1164.     return (noErr);
  1165. }
  1166.  
  1167. //////////////////////////////////////////////////////////////////////////////
  1168. //
  1169. //    HandleForkReadComplete
  1170. //
  1171. //    Called at idle time, after a file's fork has been read. If sending data
  1172. //    fork then start sending resource fork. If sending resource fork, finish
  1173. //    sending file.
  1174. //
  1175. void HandleForkReadComplete(void)
  1176. {
  1177.     CInfoPBRec                    catInfoPB;
  1178.     ParamBlockRec                pb;
  1179.     TxFSSpecPtr                    pTxItem;
  1180.     UInt32                        forkLength;
  1181.     OSErr                        err = noErr;
  1182.     
  1183.     pb.ioParam.ioRefNum = gCurForkRefNum;
  1184.     err = PBCloseSync(&pb);
  1185.  
  1186.     if (gSendingDataFork)
  1187.     {
  1188.         gSendingDataFork = false;
  1189.         err = SendEndFork(kEndDataFork);
  1190.         
  1191.         // start sending the resource fork, if there is one
  1192.         
  1193.         pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1194.         err = FSpGetCatInfo(pTxItem->pFSSpec, &catInfoPB);
  1195.         if (err == noErr)
  1196.         {
  1197.             forkLength = catInfoPB.hFileInfo.ioFlRLgLen;
  1198.             if (forkLength != 0)
  1199.             {
  1200.                 err = SendStartFork(forkLength, kStartResFork);
  1201.                 
  1202.                 if (err == noErr)
  1203.                 {
  1204.                     err = FSpOpenRF(pTxItem->pFSSpec, fsRdPerm, &gCurForkRefNum);
  1205.                     if (err == noErr)
  1206.                     {
  1207.                         gSendingResFork = true;
  1208.                         gForkComplete = false;
  1209.                         gForkWriteComplete = false;
  1210.                         err = PrimeAFork(gCurForkRefNum);
  1211.                         if (err != noErr)
  1212.                         {
  1213.                             gSendingResFork = false;
  1214.                             gForkComplete = true;
  1215.                             gForkWriteComplete = true;
  1216.                         }
  1217.                     } // end if error in open resource fork
  1218.                 } // end if error in send start fork
  1219.             }
  1220.             else
  1221.             {
  1222.                 // no resource fork, finished sending file
  1223.                 err = FinishSendFile();
  1224.             }
  1225.         } // end if error in getcatinfo
  1226.  
  1227.     } else if (gSendingResFork) {
  1228.         gSendingResFork = false;
  1229.         err = SendEndFork(kEndResFork);
  1230.         
  1231.         if (err == noErr)
  1232.             err = FinishSendFile();
  1233.     }
  1234.     
  1235.     if (err != noErr) {
  1236.         sprintf(debugStr, "Error in ForkReadComplete: %hd", err); 
  1237.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1238.     }
  1239. }
  1240.  
  1241. //////////////////////////////////////////////////////////////////////////////
  1242. //
  1243. //    SendFileInfo
  1244. //
  1245. //    Send the finder catalog info for a file.
  1246. //
  1247. static OSErr SendFileInfo (
  1248.     CInfoPBPtr                    pCatInfo)
  1249. {
  1250.     IOParamPtr                    pIOPb;            // a queue record
  1251.     FWXPacketPtr                pPktInfo;
  1252.     OSErr                        err;
  1253.     
  1254.     // send catalog information
  1255.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  1256.     if (pIOPb != nil)
  1257.     {
  1258.         SetupFWControlPB(pIOPb);
  1259.                             
  1260.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  1261.         pPktInfo->packetType = kFileInfo;
  1262.         pIOPb->ioMisc = (Ptr) kFileInfo;
  1263.         pIOPb->ioReqCount = sizeof(CInfoPBRec) + 4;        // catalog info plus packet header
  1264.         BlockMove(pCatInfo, &pPktInfo->packetData, sizeof(CInfoPBRec));
  1265.         
  1266.         err = CallFWXNode(pIOPb);
  1267.     }
  1268.     else
  1269.     {
  1270.         err = qErr;
  1271.         FWDebugStr("\pNo buffer, SendCatInfo");
  1272.     }
  1273.     return err;
  1274. }
  1275.     
  1276. //////////////////////////////////////////////////////////////////////////////
  1277. //
  1278. //    FinishSendFile
  1279. //
  1280. //    Send the file info and clean up after file transfer
  1281. //
  1282. static OSErr FinishSendFile(void)
  1283. {
  1284.     IOParamPtr                    pIOPb;            // a queue record
  1285.     FWXPacketPtr                pPktInfo;
  1286.     TxFSSpecPtr                    pTxItem;
  1287.     FWXNodeID                    txNode;
  1288.     RecvNodePtr                    pTxNodeInfo;
  1289.     OSErr                        err;
  1290.     
  1291.     // send end file
  1292.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  1293.     if (pIOPb != nil)
  1294.     {
  1295.         SetupFWControlPB(pIOPb);
  1296.                             
  1297.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  1298.         pPktInfo->packetType = kEndFile;
  1299.         pIOPb->ioMisc = (Ptr) kEndFile;
  1300.         pIOPb->ioReqCount = 4;
  1301.  
  1302.         err = CallFWXNode(pIOPb);
  1303.     }
  1304.     else
  1305.     {
  1306.         err = qErr;
  1307.         FWDebugStr("\pNo buffer, SendEndFile");
  1308.     }
  1309.     
  1310.     // dequeue and dispose of file queue entry
  1311.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1312.     txNode = pTxItem->recvNode;    // save the node id for primetime
  1313.     Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  1314.     DisposePtr((Ptr) pTxItem->pFSSpec);
  1315.     DisposePtr((Ptr) pTxItem);
  1316.     gItemsToCopy--;
  1317.  
  1318.     // get another queue item
  1319.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1320.     if (pTxItem != nil)
  1321.     {
  1322.         if (pTxItem->itemType == kFileInfo)
  1323.             SendAFile(pTxItem->pFSSpec, pTxItem->recvNode);
  1324.         else if (pTxItem->itemType == kStartFolder)
  1325.             SendAFolder(pTxItem->pFSSpec, pTxItem->recvNode);
  1326.         else if (pTxItem->itemType == kEndFolder)
  1327.             SendEndFolder();
  1328.     }
  1329.     else
  1330.     {
  1331.         gSendingFile = false;
  1332.  
  1333.         err = GetNodeInfo(txNode, &pTxNodeInfo);
  1334.         if (err == noErr)
  1335.         {
  1336.             pTxNodeInfo->pReplyTimer->nodeID = txNode;
  1337.             PrimeTime((QElemPtr) pTxNodeInfo->pReplyTimer, 10000);        // set for 10 seconds
  1338.         }                                                    // JKL ***, need to work with this value
  1339.  
  1340.         // toss the progress bar
  1341.         CleanupCopyDialog(FrontWindow());
  1342.     }
  1343.     return err;
  1344. }
  1345.  
  1346. ////////////////////////////////////////////////////////////////////////////////
  1347. //
  1348. //    HandleFWWriteComplete
  1349. //
  1350. //    Completion routine for PBWrite to FireWire node.
  1351. //    If there is a file fork currently being read, make a read with the
  1352. //    completed parameter block.
  1353. //zzz HandleFWWriteComplete, pFWPB, gFileReadQHdr, FWIXDequeue, and SetupFileReadPB
  1354. //zzz must all be held.
  1355. //
  1356. void HandleFWWriteComplete(
  1357.     IOParamPtr                pFWPB)
  1358. {
  1359.     IOParamPtr                pb;            // parameter block for doing another read
  1360.     
  1361.     if (pFWPB->ioResult == noErr) {
  1362.  
  1363.         // queue the completed parameter block
  1364.         Enqueue((QElemPtr) pFWPB, &gFileReadQHdr);
  1365.  
  1366.         // if we are still sending file data, issue another read
  1367.         if (!gForkComplete)
  1368.         {
  1369.             FWIXDequeue ((QElemPtr *) &pb, &gFileReadQHdr);
  1370.             if (pb != nil)
  1371.             {
  1372.                 SetupFileReadPB(pb);
  1373.                 PBReadAsync((ParmBlkPtr) pb);
  1374.             }
  1375.         }
  1376.         else if (gSendingDataFork || gSendingResFork)
  1377.             gForkWriteComplete = true;
  1378.     }
  1379.     else
  1380.     {
  1381.         sprintf(debugStr, "Error in PBWrite to FWiX Node: %hd", pFWPB->ioResult); 
  1382.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1383.         Enqueue((QElemPtr) pFWPB, &gFileReadQHdr);
  1384.     }
  1385. }
  1386.  
  1387. ////////////////////////////////////////////////////////////////////////////////
  1388. //
  1389. //    HandleFWControlComplete
  1390. //
  1391. //    Completion routine for PBWrite control data to FireWire node.
  1392. //zzz HandleFWControlComplete, pFWPB, and gFWControlQHdr must all be held.
  1393. //
  1394. void HandleFWControlComplete(
  1395.     IOParamPtr                pFWPB)
  1396. {
  1397.     // queue the completed parameter block
  1398.     Enqueue((QElemPtr) pFWPB, &gFWControlQHdr);
  1399. }
  1400.  
  1401. ////////////////////////////////////////////////////////////////////////////////
  1402. //
  1403. //    HandleFWReadComplete
  1404. //
  1405. //    Completion routine for PBRead to FireWire node. If the paramblock does
  1406. //    not contain any data, we assume it is cleaning up and dispose of the
  1407. //    paramblock. Otherwise queue the param block and let the receive routine handle it.
  1408. //zzz HandleFWReadComplete, pFWPB, and gReceiveQHdr must all be held.
  1409. //    
  1410. void HandleFWReadComplete(
  1411.     IOParamPtr                pFWReadPb)
  1412. {
  1413.     // JKL *** kind of a hack, the only way ioActCount should be
  1414.     // 0 is after a close call to close the node and clean up
  1415.     // any read requests. In that case the completion routine
  1416.     // will be called at normal execution time, so dispose of the buffers
  1417.     if (pFWReadPb->ioActCount == 0)
  1418.     {
  1419.         UnholdMemory(pFWReadPb->ioBuffer, pFWReadPb->ioReqCount);
  1420.         DisposePtr(pFWReadPb->ioBuffer);
  1421.         UnholdMemory((Ptr) pFWReadPb, sizeof(IOParam));
  1422.         DisposePtr((Ptr) pFWReadPb);
  1423.     }
  1424.     else
  1425.     {
  1426.         Enqueue((QElemPtr) pFWReadPb, &gReceiveQHdr);
  1427.     }
  1428. }
  1429.  
  1430. //////////////////////////////////////////////////////////////////////////////
  1431. //
  1432. //    HandleReceive
  1433. //
  1434. //    Process parameter blocks in the receive buffer. For files, create it
  1435. //    and a static FSSpec record to be used throughout the routine. Open each
  1436. //    fork as it comes, presetting eof for the fork. As fork data is received
  1437. //    copy it into a filewrite buffer, once the buffer is full, write the data.
  1438. //    Keep processing received data if there is any on the queue. Make another
  1439. //    read to the node as parameter block is handled. The idle routine
  1440. //    will call this again if the file is not completed. For folders, create
  1441. //    the folder and update the current directory id, write the folder info,
  1442. //    and once each of the folder's items are copied, set the current
  1443. //    directory id to the folder's parent
  1444. //
  1445.  
  1446. void HandleReceive(void)
  1447. {
  1448.     FWXPacketPtr            pRecvPacket;    // format the received data with our packet fields
  1449.     IOParamPtr                pPB;            // firewire read parameter block
  1450.     CurFileInfoPtr            pCurFileInfo;    // Active file for a driver ID
  1451.     FWXNodeID                senderNodeID;    // node that sent the data
  1452.     SndListHandle            hSound;            // notification sound
  1453.     UInt32                    packetType;        // what kind of data is in packet
  1454.     SInt16                    curAttributes;
  1455.     OSErr                    err;
  1456.  
  1457.     pPB = (IOParamPtr) gReceiveQHdr.qHead;
  1458.     senderNodeID = (FWXNodeID) pPB->ioNamePtr;
  1459.     err = GetCurFileInfo(senderNodeID, &pCurFileInfo, true);
  1460.     pCurFileInfo->curError = err;
  1461.     
  1462.     while (pPB != nil)
  1463.     {
  1464.         Dequeue((QElemPtr) pPB, &gReceiveQHdr);    
  1465.         pRecvPacket = (FWXPacketPtr) pPB->ioBuffer;
  1466.         packetType = (UInt32) pPB->ioMisc;
  1467.         
  1468.         if (senderNodeID != (FWXNodeID) pPB->ioNamePtr)
  1469.         {
  1470.             senderNodeID = (FWXNodeID) pPB->ioNamePtr;
  1471.             err = GetCurFileInfo(senderNodeID, &pCurFileInfo, true);
  1472.             pCurFileInfo->curError = err;
  1473.         }
  1474.         
  1475.         // catch any FireWire receive errors here.
  1476.         if (pCurFileInfo->curError == noErr)
  1477.             pCurFileInfo->curError = pPB->ioResult;
  1478.         
  1479.         if (pPB->ioResult != noErr)
  1480.             pCurFileInfo->curError = pPB->ioResult;            
  1481.             
  1482.         switch (packetType)
  1483.         {
  1484.             case kStartFile:
  1485.                 pCurFileInfo->curError = noErr;
  1486.                 err = HandleStartFile ((ConstStr255Param) &pRecvPacket->packetData,        // file name
  1487.                                         pCurFileInfo);
  1488.                 break;
  1489.             
  1490.             case kStartDataFork:
  1491.                 if (pCurFileInfo->curError == noErr)
  1492.                 {
  1493.                     err = FSpOpenDF(pCurFileInfo->pCurFileSpec, fsWrPerm, &pCurFileInfo->curFileRefNum);
  1494.                     pCurFileInfo->recvLength = 0;
  1495.                     pCurFileInfo->forkLength = (UInt32) pRecvPacket->packetData;
  1496.                     if (err == noErr)
  1497.                         err = HandleStartFork(pPB, pCurFileInfo->forkLength, pCurFileInfo->curFileRefNum);
  1498.                 }
  1499.                 break;
  1500.             
  1501.             case kStartResFork:
  1502.                 if (pCurFileInfo->curError == noErr)
  1503.                 {
  1504.                     err = FSpOpenRF(pCurFileInfo->pCurFileSpec, fsWrPerm, &pCurFileInfo->curFileRefNum);
  1505.                     pCurFileInfo->recvLength = 0;
  1506.                     pCurFileInfo->forkLength = (UInt32) pRecvPacket->packetData;
  1507.                     if (err == noErr)
  1508.                         err = HandleStartFork(pPB, pCurFileInfo->forkLength, pCurFileInfo->curFileRefNum);
  1509.                 }
  1510.                 break;
  1511.             
  1512.             case kForkData:
  1513.                 if (pCurFileInfo->curError == noErr)
  1514.                 {
  1515.                     pCurFileInfo->recvLength += pPB->ioActCount;
  1516.                     err = HandleForkData(pPB, pCurFileInfo->curFileRefNum);
  1517.                 }
  1518.                 else
  1519.                 {
  1520.                     // return packet to data buffer queue
  1521.                     pPB->ioTrap = kFWXRead;
  1522.                     pPB->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  1523.                     pPB->ioReqCount = kFWReadDataBufSize;
  1524.                     pPB->ioMisc = (Ptr) kForkData;
  1525.                     CallFWXNode(pPB);
  1526.                 }
  1527.                 break;
  1528.                 
  1529.             case kEndDataFork:
  1530.             case kEndResFork:
  1531.                 if (pCurFileInfo->curError == noErr)
  1532.                 {
  1533.                     pPB->ioRefNum = pCurFileInfo->curFileRefNum;
  1534.                     err = PBCloseSync((ParmBlkPtr) pPB);
  1535.                     if (pCurFileInfo->recvLength != pCurFileInfo->forkLength)
  1536.                         err = ioErr;
  1537.                 }
  1538.                 break;
  1539.                 
  1540.             case kFileInfo:
  1541.                 if (pCurFileInfo->curError == noErr)
  1542.                 {
  1543.                     err = HandleFileInfo (pCurFileInfo->pCurFileSpec,
  1544.                                           (CInfoPBPtr) &pRecvPacket->packetData);
  1545.                 }
  1546.                 break;
  1547.             
  1548.             case kEndFile:
  1549.                 FlushVol(nil, 0);
  1550.                 break;
  1551.             
  1552.             case kStartFolder:
  1553.                 pCurFileInfo->curError = noErr;
  1554.                 err = HandleStartFolder ((ConstStr255Param) &pRecvPacket->packetData,        // folder name
  1555.                                          &(pCurFileInfo->curDirID));
  1556.                 break;
  1557.                 
  1558.             case kFolderInfo:
  1559.                 if (pCurFileInfo->curError == noErr)
  1560.                 {
  1561.                     err = HandleFolderInfo ((CInfoPBPtr) &pRecvPacket->packetData,
  1562.                                              pCurFileInfo->curDirID);
  1563.                 }
  1564.                 break;
  1565.                 
  1566.             case kEndFolder:
  1567.                 HandleEndFolder (&pCurFileInfo->curDirID);
  1568.                 break;
  1569.                 
  1570.             case kNodeInfoRequest:
  1571.                 err = HandleNodeInfoRequest ((ConstStr255Param) &pRecvPacket->packetData,
  1572.                                               senderNodeID);
  1573.                 break;
  1574.         
  1575.             case kNodeInfoReply:
  1576.                 err = HandleNodeInfoReply ((ConstStr255Param) &pRecvPacket->packetData,
  1577.                                            senderNodeID);
  1578.                 break;
  1579.         
  1580.             case kQuitNotify:
  1581.                 err = HandleNodeQuit (senderNodeID);
  1582.                 break;
  1583.                 
  1584.             case kTransferStopped:
  1585.                 err = HandleStopTransfer (pCurFileInfo);
  1586.                 break;
  1587.                 
  1588.             case kPreflightCopy:
  1589.                 err = HandleCheckItem (pCurFileInfo,
  1590.                                        senderNodeID,
  1591.                                        (UInt32) pRecvPacket->packetData,      
  1592.                                        (ConstStr255Param) (((Ptr) &pRecvPacket->packetData) + 4));
  1593.                 break;
  1594.                 
  1595.             case kPreflightReply:
  1596.                 err = HandlePreflightReply (senderNodeID,
  1597.                                             (SInt32) pRecvPacket->packetData,      
  1598.                                             (ConstStr255Param) (((Ptr) &pRecvPacket->packetData) + 4));
  1599.                 break;
  1600.                 
  1601.             case kReceiveReply:
  1602.                 err = HandleReceiveComplete (senderNodeID,
  1603.                                              (UInt32) pRecvPacket->packetData,        // error code
  1604.                                              *((UInt32 *) (pPB->ioBuffer + 12)),    // fork length
  1605.                                              *((UInt32 *) (pPB->ioBuffer + 16)));    // bytes received
  1606.                 break;
  1607.             
  1608.             default:
  1609.                 err = paramErr;
  1610.                 break;
  1611.         }
  1612.         
  1613.         // update current error state if previous state was no error
  1614.         if (pCurFileInfo->curError == noErr)
  1615.             pCurFileInfo->curError = err;
  1616.         
  1617.         if (err != noErr)
  1618.         {
  1619.             sprintf(debugStr, "Error in handle receive: %hd", err); // JKL *** handle this error
  1620.             FWDebugStr((ConstStr255Param) c2pstr (debugStr));
  1621.         }
  1622.         
  1623.         if (packetType != kForkData)
  1624.         {
  1625.             // nil the misc field so fwxread knows its a control packet
  1626.             pPB->ioTrap = kFWXRead;
  1627.             pPB->ioReqCount = kFWReadControlBufSize;
  1628.             pPB->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  1629.             pPB->ioMisc = nil;
  1630.             CallFWXNode(pPB);
  1631.         }
  1632.     
  1633.         if ((packetType == kEndFile) || (packetType == kEndFolder) ||
  1634.             (packetType == kStartFile) || (packetType == kStartFolder))
  1635.         {
  1636.             if (pCurFileInfo->curError != noErr)
  1637.             {
  1638.                 SendReceiveComplete (pCurFileInfo->curError,
  1639.                                      senderNodeID,
  1640.                                      pCurFileInfo->forkLength,
  1641.                                      pCurFileInfo->recvLength,
  1642.                                      pCurFileInfo->pCurFileSpec->name);
  1643.                 // JKL *** delete the file or folder if it exists,
  1644.                 // for now we leave it for debugging purposes
  1645.             }
  1646.         }        
  1647.         pPB = (IOParamPtr) gReceiveQHdr.qHead;
  1648.     }
  1649.     
  1650.     // JKL *** Need to have some type of start transaction/end transaction code. Its possible
  1651.     // that the endfile or endfolder message would be that last on the current queue but not
  1652.     // the last file or folder in the entire send. This would do the notification too early.
  1653.     if ((packetType == kEndFile) || (packetType == kEndFolder))
  1654.     {
  1655.         SendReceiveComplete (pCurFileInfo->curError,
  1656.                              senderNodeID,
  1657.                              pCurFileInfo->forkLength,
  1658.                              pCurFileInfo->recvLength,
  1659.                              pCurFileInfo->pCurFileSpec->name);
  1660.         if (err == noErr)
  1661.         {
  1662.             if (gpFWXAppData->fwixPrefs & kNotifyOpen)
  1663.                 OpenDropFolder();
  1664.             if (gpFWXAppData->fwixPrefs & kNotifyFlash)
  1665.             {
  1666.                 if (gpFWXAppData->pNotifyRec->nmRefCon == kNoNotificationPosted)
  1667.                 {
  1668.                     gpFWXAppData->pNotifyRec->nmRefCon = kNotificationPosted;
  1669.                     NMInstall(gpFWXAppData->pNotifyRec);
  1670.                 }
  1671.             }
  1672.             if (gpFWXAppData->fwixPrefs & kNotifySound)
  1673.             {
  1674.                 hSound = (SndListHandle) GetNamedResource('snd ', gpFWXAppData->fwixNotifySound);
  1675.                 if (hSound != nil)
  1676.                 {
  1677.                     curAttributes = GetResAttrs((Handle) hSound);
  1678.                     if (curAttributes & resPurgeable)
  1679.                         HNoPurge((Handle) hSound);
  1680.                     SndPlay(nil, hSound, false);
  1681.                     SetResAttrs((Handle) hSound, curAttributes);
  1682.                     ReleaseResource((Handle) hSound);
  1683.                 }
  1684.             }
  1685.             if (gpFWXAppData->fwixPrefs & kNotifyAlert)
  1686.                 HandleNoteAlert(kReceiveAlertID);
  1687.         }
  1688.     }
  1689. }
  1690.  
  1691. //////////////////////////////////////////////////////////////////////////////
  1692. //
  1693. //    HandleReceiveComplete
  1694. //
  1695. //    Display an error if the transfer does not complete.
  1696. //
  1697. static OSErr HandleReceiveComplete(
  1698.     FWXNodeID            recvNode,
  1699.     UInt32                result,
  1700.     UInt32                forkLength,
  1701.     UInt32                lengthRecvd)
  1702. {
  1703.     RecvNodePtr            pRecvNodeInfo;
  1704.     AESendRecPtr        pAESendElem;
  1705.     Str31                s;
  1706.     OSErr                err;
  1707.     
  1708.     err = GetNodeInfo(recvNode, &pRecvNodeInfo);
  1709.     if (err == noErr)
  1710.     {
  1711.         RmvTime((QElemPtr) pRecvNodeInfo->pReplyTimer);
  1712.         pRecvNodeInfo->pReplyTimer->timerTask.tmWakeUp = 0;
  1713.         pRecvNodeInfo->pReplyTimer->timerTask.tmReserved = 0;
  1714.         InsTime((QElemPtr) pRecvNodeInfo->pReplyTimer);
  1715.         
  1716.         if (result != noErr)
  1717.         {
  1718.             if (result == ioErr)
  1719.             {
  1720.                 NumToString((forkLength - lengthRecvd), s);
  1721.                 ParamText(s, "\p", "\p", "\p");
  1722.                 HandleCautionAlert(kIOErrorAlertID);
  1723.             }
  1724.             else if (result == fBsyErr)
  1725.             {
  1726.                 HandleCautionAlert(kItemBusyErrAlertID);
  1727.             }
  1728.             else
  1729.             {
  1730.                 NumToString(result, s);
  1731.                 ParamText(s, "\p", "\p", "\p");
  1732.                 HandleCautionAlert(kRecvErrorAlertID);
  1733.             }
  1734.         }
  1735.     }
  1736.     
  1737.     if (!(gSendingFile || gCheckingTransfer))
  1738.     {
  1739.         pAESendElem = (AESendRecPtr) gAESendQHdr.qHead;
  1740.         if (pAESendElem != nil)
  1741.         {
  1742.             Dequeue((QElemPtr) pAESendElem, &gAESendQHdr);
  1743.             SendFSSpecListToSelf(pAESendElem->recvNode, pAESendElem->pSendItemsList, pAESendElem->numSendItems);
  1744.             DisposePtr((Ptr) pAESendElem->pSendItemsList);
  1745.             DisposePtr((Ptr) pAESendElem);
  1746.         }
  1747.     }
  1748.  
  1749.     return err;
  1750. }
  1751.  
  1752. //////////////////////////////////////////////////////////////////////////////
  1753. //
  1754. //    HandlePreflightReply
  1755. //
  1756. //    Take care of the reply to the send check. This is a long one. If there is
  1757. //    an error from the reply, handle it according to error level or user set
  1758. //    preference. If item is going to be sent, have to remove it from the
  1759. //    send check list and put it on the transfer queue. If it is the last checked
  1760. //    item, then tell senditems to start going.
  1761. //
  1762. static OSErr HandlePreflightReply(
  1763.     FWXNodeID                receiveNodeID,
  1764.     SInt32                    preflightResult,
  1765.     ConstStr255Param        itemName)
  1766. {
  1767.     RecvNodePtr                pRecvNode;
  1768.     NodeSendItemPtr            pSendItem, pTempItem;
  1769.     UInt32                    index;
  1770.     UInt32                    itemCount;
  1771.     OSErr                    err;
  1772.     Boolean                    okToSend = true;
  1773.     
  1774.     // get a pointer to the node record
  1775.     err = GetNodeInfo(receiveNodeID, &pRecvNode);
  1776.     if (err == noErr) {
  1777.         ParamText(itemName, pRecvNode->nodeName, "\p", "\p");
  1778.     
  1779.         // check for errors and handle them according to prefs
  1780.         // if not enough space or unknown error, clear list and
  1781.         // show alert, if file exists error, handle according to
  1782.         // prefs
  1783.         if (preflightResult != 0) {
  1784.             switch (preflightResult)
  1785.             {
  1786.                 case kSpaceError:
  1787.                     StopTransfer(pRecvNode);
  1788.                     HandleStopAlert(kSpaceErrAlertID);
  1789.                     okToSend = false;
  1790.                     break;
  1791.                 case kItemExistsError:
  1792.                     StopTransfer(pRecvNode);
  1793.                     HandleStopAlert(kItemExistsErrAlertID);
  1794.                     okToSend = false;
  1795.                     break;
  1796.                 case fBsyErr:
  1797.                     StopTransfer(pRecvNode);
  1798.                     HandleStopAlert(kItemBusyErrAlertID);
  1799.                     okToSend = false;
  1800.                     break;
  1801.                 case nsvErr:
  1802.                     StopTransfer(pRecvNode);
  1803.                     HandleStopAlert(kNSVErrAlertID);
  1804.                     okToSend = false;
  1805.                     break;
  1806.                 default:
  1807.                     StopTransfer(pRecvNode);
  1808.                     HandleStopAlert(kUnknownErrAlertID);
  1809.                     okToSend = false;
  1810.                     break;
  1811.             }
  1812.         }
  1813.         
  1814.         if (okToSend)
  1815.         {
  1816.             // find the send item record in the list, dequeue it and call sendfsitem,
  1817.             // if this is the last item record, tell sendfsitem to start sending
  1818.             pSendItem = pRecvNode->pTxItemList;
  1819.             if (pSendItem == nil)
  1820.             {
  1821.                 err = resNotFound;
  1822.             }
  1823.             else
  1824.             {
  1825.                 // traverse the list looking for the item name
  1826.                 itemCount = 1;
  1827.                 while (pSendItem->pNextSendItem != nil)
  1828.                 {
  1829.                     // find the item record that matches the name
  1830.                     if (EqualString(itemName, pSendItem->sendItemSpec.name, true, true))
  1831.                         break;
  1832.                     pSendItem = pSendItem->pNextSendItem;
  1833.                     itemCount++;
  1834.                 }
  1835.                             
  1836.                 // now have to remove the item from the list
  1837.                 if (itemCount == 1)
  1838.                 {
  1839.                     pRecvNode->pTxItemList = pSendItem->pNextSendItem;
  1840.                 }
  1841.                 else
  1842.                 {
  1843.                     // traverse the list finding the item before this one
  1844.                     // set its next pointer to the found item's next pointer
  1845.                     pTempItem = pRecvNode->pTxItemList;
  1846.                     for (index = 2; index < itemCount; index++)
  1847.                         pTempItem = pTempItem->pNextSendItem;
  1848.                     pTempItem->pNextSendItem = pSendItem->pNextSendItem;
  1849.                 }
  1850.                 
  1851.                 // now add the item to the send list then delete it
  1852.                 // if this is the last item in the list, start the send
  1853.                 if (pRecvNode->pTxItemList == nil)
  1854.                     SendFSItem(&pSendItem->sendItemSpec, receiveNodeID, true);
  1855.                 else
  1856.                     SendFSItem(&pSendItem->sendItemSpec, receiveNodeID, false);
  1857.                 DisposePtr((Ptr) pSendItem);
  1858.             }
  1859.         }
  1860.     }
  1861.     return err;
  1862. }
  1863.     
  1864. //////////////////////////////////////////////////////////////////////////////
  1865. //
  1866. //    CleanupTxError
  1867. //
  1868. //    Clean up send lists on error.
  1869. //
  1870. static void CleanupTxError(
  1871.     RecvNodePtr                pNode)
  1872. {
  1873.     NodeSendItemPtr            pSendItem, pTempItem;
  1874.     TxFSSpecPtr                pTxItem;
  1875.  
  1876.     pSendItem = pNode->pTxItemList;
  1877.     if (pSendItem != nil)
  1878.     {
  1879.         do
  1880.         {
  1881.             pTempItem = pSendItem;
  1882.             pSendItem = pSendItem->pNextSendItem;
  1883.             DisposePtr((Ptr) pTempItem);
  1884.         } while (pSendItem != nil);
  1885.     }
  1886.     pNode->pTxItemList = nil;
  1887.     
  1888.     // clear the transfer list, dequeue and dispose of file queue entry
  1889.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1890.     while (pTxItem != nil)
  1891.     {
  1892.         Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  1893.         DisposePtr((Ptr) pTxItem->pFSSpec);
  1894.         DisposePtr((Ptr) pTxItem);
  1895.  
  1896.         // get another queue item
  1897.         pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1898.     }
  1899.     gItemsToCopy = 0;
  1900.     gBytesToCopy = 0;
  1901. }
  1902.     
  1903. //////////////////////////////////////////////////////////////////////////////
  1904. //
  1905. //    DirectoryBusy
  1906. //
  1907. //    Check to see if a file in the directory to be deleted is in use or locked.
  1908. //
  1909. static Boolean DirectoryBusy (
  1910.     SInt32                    dirID)
  1911. {
  1912.     Str32                fName;
  1913.     UInt32                savedDir;
  1914.     SInt16                index;
  1915.     OSErr                err;
  1916.     Boolean                isFolder;
  1917.     Boolean                isBusy = false;
  1918.  
  1919.     index = 0;
  1920.     do {
  1921.         gCatInfoPB.dirInfo.ioDrDirID = dirID;
  1922.         index++;
  1923.         gCatInfoPB.dirInfo.ioFDirIndex = index;
  1924.         gCatInfoPB.dirInfo.ioNamePtr = fName;
  1925.         err = PBGetCatInfoSync(&gCatInfoPB);
  1926.         if (err == noErr)
  1927.         {
  1928.             savedDir = dirID;
  1929.             isFolder = gCatInfoPB.dirInfo.ioFlAttrib & ioDirMask;
  1930.             if (isFolder)
  1931.             {
  1932.                 savedDir = gCatInfoPB.dirInfo.ioDrDirID;
  1933.                 err = DeleteDirectoryContents(gCatInfoPB.dirInfo.ioDrDirID);
  1934.                 gCatInfoPB.dirInfo.ioNamePtr = nil;
  1935.             }
  1936.             if (err == noErr)
  1937.             {
  1938.                 gCatInfoPB.dirInfo.ioDrDirID = savedDir;
  1939.                 if (!isFolder)
  1940.                     isBusy = gCatInfoPB.hFileInfo.ioFlAttrib & 0x80;
  1941.             }
  1942.         }
  1943.     } while ((err == noErr) && (!isBusy));
  1944.  
  1945.     if (err == fnfErr)
  1946.         err = noErr;
  1947.  
  1948.     return isBusy;
  1949. }
  1950.  
  1951. //////////////////////////////////////////////////////////////////////////////
  1952. //
  1953. //    HandleCheckItem
  1954. //
  1955. //    Check to see if we can safely receive the pending item.
  1956. //
  1957. static OSErr HandleCheckItem(
  1958.     CurFileInfoPtr            pCurFileInfo,
  1959.     FWXNodeID                sendingNodeID,
  1960.     UInt32                    itemSize,
  1961.     ConstStr255Param        itemName)
  1962. {
  1963.     CInfoPBRec                catInfo;
  1964.     HParamBlockRec            pb;
  1965.     IOParamPtr                pIOPb;
  1966.     FWXPacketPtr            pPktInfo;
  1967.     SInt32                    checkResult;
  1968.     OSErr                    makeErr = noErr,
  1969.                             sizeErr = noErr,
  1970.                             err;
  1971.     Boolean                    itemExists = false,
  1972.                             itemBusy = false,
  1973.                             sizeOK = false;
  1974.     
  1975.     err = InitRecvFolder(&pCurFileInfo->curDirID);
  1976.     if (err == noErr)
  1977.     {
  1978.     // check for item exists
  1979.     makeErr = FSMakeFSSpec (gpFWXAppData->fwixReceiveFolder.vRefNum,
  1980.                             pCurFileInfo->curDirID,
  1981.                             itemName,
  1982.                             pCurFileInfo->pCurFileSpec);
  1983.     if (makeErr == noErr)
  1984.     {
  1985.         // item exists, set flag according to prefs
  1986.         if (gpFWXAppData->fwixPrefs & kConflictCancel)
  1987.             itemExists = true;
  1988.         else if (gpFWXAppData->fwixPrefs & kConflictOverwrite)
  1989.         {
  1990.             err = FSpGetCatInfo(pCurFileInfo->pCurFileSpec, &catInfo);
  1991.             if (err == noErr)
  1992.             {
  1993.                 if (catInfo.dirInfo.ioFlAttrib & ioDirMask)
  1994.                     itemBusy = DirectoryBusy(catInfo.dirInfo.ioDrDirID);
  1995.                 else
  1996.                     itemBusy = catInfo.hFileInfo.ioFlAttrib & 0x80;
  1997.             }
  1998.         }            
  1999.     }
  2000.     else if (makeErr == fnfErr)
  2001.         makeErr = noErr;
  2002.  
  2003.     // check item size
  2004.     if (makeErr == noErr)
  2005.     {
  2006.         pb.volumeParam.ioVRefNum = pCurFileInfo->pCurFileSpec->vRefNum;
  2007.         pb.volumeParam.ioNamePtr = nil;
  2008.         pb.volumeParam.ioVolIndex = 0;
  2009.  
  2010.         sizeErr = PBHGetVInfoSync(&pb);
  2011.         if (sizeErr == noErr)
  2012.             sizeOK = (pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz) > itemSize;
  2013.     }
  2014.     }
  2015.     
  2016.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  2017.     if (pIOPb != nil)
  2018.     {
  2019.         SetupFWControlPB(pIOPb);
  2020.         // SetupFWControlPB will leave an invalid node id in nameptr at this point
  2021.         pIOPb->ioNamePtr = (StringPtr) sendingNodeID;
  2022.         
  2023.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  2024.         pPktInfo->packetType = kPreflightReply;
  2025.         pIOPb->ioMisc = (Ptr) kPreflightReply;
  2026.         checkResult = 0;
  2027.         if (err)
  2028.             checkResult = err;
  2029.         else if (!sizeOK)
  2030.             checkResult = kSpaceError;
  2031.         else if (itemExists)
  2032.             checkResult = kItemExistsError;
  2033.         else if (itemBusy)
  2034.             checkResult = fBsyErr;
  2035.         if (makeErr || sizeErr)
  2036.             checkResult = kUnknownError;
  2037.  
  2038.         pPktInfo->packetData = (Ptr) checkResult;
  2039.         BlockMove(itemName, ((Ptr) &pPktInfo->packetData) + 4, itemName[0] + 1);
  2040.         pIOPb->ioReqCount = itemName[0] + 1 + 4 + 4;    // length of string plus packet header plus size
  2041.         
  2042.         err = CallFWXNode(pIOPb);
  2043.     }
  2044.     else
  2045.     {
  2046.         err = qErr;
  2047.         FWDebugStr("\pNo buffer for PreflightReply");
  2048.     }
  2049.  
  2050.     return err;
  2051. }
  2052.  
  2053.  
  2054. //////////////////////////////////////////////////////////////////////////////
  2055. //
  2056. //    SendReceiveComplete
  2057. //
  2058. //    Send a receive notification to the sending machine.
  2059. //
  2060. static OSErr SendReceiveComplete (
  2061.     OSErr                    sendError,
  2062.     FWXNodeID                senderID,
  2063.     UInt32                    forkLength,
  2064.     UInt32                    recvCount,
  2065.     ConstStr255Param        name)
  2066. {
  2067.     IOParamPtr                pIOPb;
  2068.     FWXPacketPtr            pPktInfo;
  2069.     OSErr                    err;
  2070.     
  2071.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  2072.     if (pIOPb != nil)
  2073.     {
  2074.         SetupFWControlPB(pIOPb);
  2075.         // SetupFWControlPB will leave an invalid node id in nameptr at this point
  2076.         pIOPb->ioNamePtr = (StringPtr) senderID;
  2077.         
  2078.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  2079.         pPktInfo->packetType = kReceiveReply;
  2080.         pIOPb->ioMisc = (Ptr) kReceiveReply;
  2081.  
  2082.         pPktInfo->packetData = (Ptr) sendError;
  2083.         ((UInt32 *) pIOPb->ioBuffer)[3] = forkLength;
  2084.         ((UInt32 *) pIOPb->ioBuffer)[4] = recvCount;
  2085.         BlockMove(name, ((Ptr) &pPktInfo->packetData) + 12, name[0]+1);
  2086.         pIOPb->ioReqCount = 16 + name[0] + 1;                        // length of header plus error plus two fork counts
  2087.         
  2088.         err = CallFWXNode(pIOPb);
  2089.     }
  2090.     else
  2091.     {
  2092.         err = qErr;
  2093.         FWDebugStr("\pNo buffer for SendReceiveReply");
  2094.     }
  2095.     return err;
  2096. }
  2097.  
  2098.  
  2099. //////////////////////////////////////////////////////////////////////////////
  2100. //
  2101. //    GetCurFileInfo
  2102. //
  2103. //    Scan the received file queue for an entry matching the node id.
  2104. //    Return the pointer to the file info, create one if not found. Make
  2105. //    sure the drop folder exists and set receive directory id to it.
  2106. //
  2107. //    JKL ***, when do we dispose of this
  2108. //
  2109.  
  2110. OSErr GetCurFileInfo(
  2111.     FWXNodeID                sourceID,
  2112.     CurFileInfoPtr            *hCurFileInfo,
  2113.     Boolean                    createNew)
  2114. {
  2115.     CurFileInfoPtr            temp;
  2116.     OSErr                    err = noErr;
  2117.     
  2118.     temp = (CurFileInfoPtr) gCurFileQHdr.qHead;
  2119.     while ((temp != nil) && (temp->curFileSenderID != sourceID))
  2120.         temp = (CurFileInfoPtr) temp->qLink;
  2121.     
  2122.     if ((temp == nil) && createNew)
  2123.     {
  2124.         temp = (CurFileInfoPtr) NewPtrClear(sizeof (CurFileInfo));
  2125.         if (temp == nil)
  2126.             return memFullErr;
  2127.  
  2128.         temp->pCurFileSpec = (FSSpecPtr) NewPtr(sizeof(FSSpec));
  2129.         if (temp->pCurFileSpec == nil)
  2130.         {
  2131.             DisposePtr((Ptr) temp);
  2132.             return memFullErr;
  2133.         }
  2134.         
  2135.         temp->curFileSenderID = sourceID;
  2136.         err = InitRecvFolder(&temp->curDirID);
  2137.         temp->curError = noErr;
  2138.         Enqueue((QElemPtr) temp, &gCurFileQHdr);
  2139.     }
  2140.     
  2141.     if ((temp == nil) && (!createNew))
  2142.         err = resNotFound;        // JKL *** what error?
  2143.     *hCurFileInfo = temp;
  2144.     return err;    
  2145. }
  2146.     
  2147.  
  2148. //////////////////////////////////////////////////////////////////////////////
  2149. //
  2150. //    InitRecvFolder
  2151. //
  2152. //    Create the receive folder if it does not exist.
  2153. //
  2154.  
  2155. OSErr InitRecvFolder(
  2156.     SInt32            *dirID)
  2157. {
  2158.     CInfoPBRec        catInfo;
  2159.     OSErr            err;
  2160.  
  2161.     err = FSpGetCatInfo(&(gpFWXAppData->fwixReceiveFolder), &catInfo);
  2162.     if (err != noErr) {
  2163.         err = FSpDirCreate(&(gpFWXAppData->fwixReceiveFolder), smSystemScript, dirID);    
  2164.     } else {
  2165.         *dirID = catInfo.dirInfo.ioDrDirID;
  2166.     }
  2167.     
  2168.     return err;    
  2169. }
  2170.     
  2171.  
  2172. //////////////////////////////////////////////////////////////////////////////
  2173. //
  2174. //    HandleStopTransfer
  2175. //
  2176. //    Take care of transfer being stopped, close any open fork, requeue param
  2177. //    block. Delete the current item. Clear receive queue. Reset receive directory
  2178. //    id to top level of drop folder.
  2179. //
  2180.  
  2181. OSErr HandleStopTransfer(
  2182.     CurFileInfoPtr        pCurFileInfo)
  2183. {
  2184.     IOParamPtr            pPB;            // firewire read parameter block
  2185.     ParamBlockRec        pb;
  2186.     OSErr                err = noErr;
  2187.     
  2188.     if (pCurFileInfo->curFileRefNum != 0)
  2189.     {
  2190.         pb.ioParam.ioRefNum = pCurFileInfo->curFileRefNum;
  2191.         err = PBCloseSync(&pb);
  2192.         pCurFileInfo->curFileRefNum = 0;
  2193.     }
  2194.     
  2195.     // delete current item, JKL *** if item is a folder, what to do?
  2196.     FSpDelete(pCurFileInfo->pCurFileSpec);
  2197.  
  2198.     pPB = (IOParamPtr) gReceiveQHdr.qHead;
  2199.     while (pPB != nil)
  2200.     {
  2201.         Dequeue((QElemPtr) pPB, &gReceiveQHdr);
  2202.         
  2203.         // take all of the received packets off the queue and send them
  2204.         // back to the driver
  2205.         CallFWXNode(pPB);
  2206.         pPB = (IOParamPtr) gReceiveQHdr.qHead;
  2207.     }
  2208.     
  2209.     // reset current directory if
  2210.     InitRecvFolder(&pCurFileInfo->curDirID);
  2211.     return err;
  2212. }
  2213.  
  2214. //////////////////////////////////////////////////////////////////////////////
  2215. //
  2216. //    HandleEndFolder
  2217. //
  2218. //    Set the receive folder directory to the current directory's parent
  2219. //
  2220. static OSErr HandleEndFolder(
  2221.     SInt32                    *curDirID)
  2222. {
  2223.     FSSpec                    curFolderSpec;
  2224.     OSErr                    err;
  2225.     
  2226.     err = FSMakeFSSpec (gpFWXAppData->fwixReceiveFolder.vRefNum,
  2227.                         *curDirID,
  2228.                         nil,
  2229.                         &curFolderSpec);
  2230.     *curDirID = curFolderSpec.parID;
  2231.     
  2232.     return err;
  2233. }
  2234.  
  2235. //////////////////////////////////////////////////////////////////////////////
  2236. //
  2237. //    HandleNodeInfoRequest
  2238. //
  2239. //    If the nodeName has not been received yet, store it in the node record
  2240. //    force a window update, and send our nodeName to the source node.
  2241. //
  2242. static OSErr HandleNodeInfoRequest(
  2243.     ConstStr255Param        nodeName,
  2244.     FWXNodeID                nodeID)
  2245. {
  2246.     RecvNodePtr                pRecvNode;
  2247.     GrafPtr                    pWindowPort;
  2248.     OSErr                    err = noErr;
  2249.     
  2250.     err = GetNodeInfo(nodeID, &pRecvNode);
  2251.     if (err == resNotFound)
  2252.     {
  2253.         // init the new node
  2254.         err = InitRecvNode(nodeID, nodeName);
  2255.         
  2256.         ShowWindow(gpFWXAppData->pSenderWindow);
  2257.         pWindowPort = (GrafPtr) GetWindowPort(gpFWXAppData->pSenderWindow);
  2258.         SetPortWindowPort(pWindowPort);
  2259.         InvalRect(&(pWindowPort->portRect));
  2260.         EnableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2261.         EnableItem(GetMenuHandle(kViewMenuID), 0);
  2262.         DrawMenuBar();
  2263.     }
  2264.                 
  2265.     err = SendFWXInfo(nodeID, kNodeInfoReply);                
  2266.     return err;
  2267. }
  2268.  
  2269.  
  2270. //////////////////////////////////////////////////////////////////////////////
  2271. //
  2272. //    HandleNodeInfoReply
  2273. //
  2274. //    If the nodeName has not been received yet, store it in the node record
  2275. //    and force a window update.
  2276. //
  2277. static OSErr HandleNodeInfoReply(
  2278.     ConstStr255Param        nodeName,
  2279.     FWXNodeID                nodeID)
  2280. {
  2281.     RecvNodePtr                pRecvNode;
  2282.     GrafPtr                    pWindowPort;
  2283.     OSErr                    err = noErr;
  2284.     
  2285.     err = GetNodeInfo(nodeID, &pRecvNode);
  2286.     if (err == resNotFound)
  2287.     {
  2288.         // init the new node
  2289.         err = InitRecvNode(nodeID, nodeName);
  2290.         
  2291.         ShowWindow(gpFWXAppData->pSenderWindow);
  2292.         pWindowPort = (GrafPtr) GetWindowPort(gpFWXAppData->pSenderWindow);
  2293.         SetPortWindowPort(pWindowPort);
  2294.         InvalRect(&(pWindowPort->portRect));
  2295.         EnableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2296.         EnableItem(GetMenuHandle(kViewMenuID), 0);
  2297.         DrawMenuBar();
  2298.     }
  2299.     return err;
  2300. }
  2301.  
  2302.  
  2303. //////////////////////////////////////////////////////////////////////////////
  2304. //
  2305. //    HandleNodeQuit
  2306. //
  2307. //    Take care of a fwix node quitting, clean up window and node record.
  2308. //
  2309. static OSErr HandleNodeQuit(
  2310.     FWXNodeID                nodeID)
  2311. {
  2312.     WindowDataPtr            pWinData;
  2313.     RecvNodePtr                pRecvNode;
  2314.     Boolean                    foundNodeID;
  2315.     OSErr                    err = noErr;
  2316.     
  2317.     if (gSendingFile || gCheckingTransfer)
  2318.     {
  2319.         if (nodeID == ((TxFSSpecPtr) gSendQHdr.qHead)->recvNode)
  2320.         {
  2321.             err = GetNodeInfo(nodeID, &pRecvNode);
  2322.             if (err == noErr)
  2323.                 StopTransfer(pRecvNode);
  2324.             HandleStopAlert(kReceiverQuitAlertID);
  2325.         }
  2326.     }
  2327.  
  2328.     foundNodeID = false;
  2329.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  2330.     pRecvNode = pWinData->pRecvNodeList;
  2331.     do
  2332.     {
  2333.         if (pRecvNode->nodeID == nodeID)
  2334.         {
  2335.             foundNodeID = true;
  2336.             break;
  2337.         }
  2338.         pRecvNode = pRecvNode->pNextNode;
  2339.         
  2340.     } while ((pRecvNode != nil) && !foundNodeID);
  2341.         
  2342.     // Remove the node from the receive node list.
  2343.     if (foundNodeID)
  2344.     {
  2345.         // remove the node from the list
  2346.         if (pRecvNode->pNextNode != nil)
  2347.             pRecvNode->pNextNode->pPreviousNode = pRecvNode->pPreviousNode;
  2348.             
  2349.         if (pRecvNode->pPreviousNode != nil)
  2350.             pRecvNode->pPreviousNode->pNextNode = pRecvNode->pNextNode;
  2351.         else
  2352.             pWinData->pRecvNodeList = pRecvNode->pNextNode;
  2353.         
  2354.         if (pRecvNode->pReplyTimer != nil)
  2355.         {
  2356.             if (pRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  2357.                 DisposeRoutineDescriptor(pRecvNode->pReplyTimer->timerTask.tmAddr);
  2358.             DisposePtr((Ptr) pRecvNode->pReplyTimer);
  2359.         }
  2360.         DisposePtr((Ptr) pRecvNode);
  2361.         pWinData->numRecvNodes--;
  2362.         
  2363.         if (pWinData->numRecvNodes == 0)
  2364.         {
  2365.             HideWindow(gpFWXAppData->pSenderWindow);
  2366.             DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2367.             DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2368.             DisableItem(GetMenuHandle(kViewMenuID), 0);
  2369.             DrawMenuBar();
  2370.         }
  2371.         else
  2372.         {
  2373.             // Force an update
  2374.             AdjustNodeIcons (pWinData, &gpFWXAppData->pSenderWindow->portRect);
  2375.             AdjustScrollBars (gpFWXAppData->pSenderWindow, false);
  2376.             InvalRect (&gpFWXAppData->pSenderWindow->portRect);
  2377.         }
  2378.     }
  2379.     
  2380.     return err;
  2381. }
  2382.  
  2383.  
  2384. //////////////////////////////////////////////////////////////////////////////
  2385. //
  2386. //    HandleStartFolder
  2387. //
  2388. //    Create the new folder and update receive folder directory id
  2389. //
  2390. static OSErr HandleStartFolder(
  2391.     ConstStr255Param        folderName,
  2392.     SInt32                    *curDirID)
  2393. {
  2394.     FSSpec                    newFolderSpec;
  2395.     OSErr                    err;
  2396.  
  2397.     err = FSMakeFSSpec (gpFWXAppData->fwixReceiveFolder.vRefNum,
  2398.                         *curDirID,
  2399.                         folderName,
  2400.                         &newFolderSpec);
  2401.     if (err != noErr)
  2402.     {
  2403.         if (err == fnfErr)        // should get fnfErr for new folder    
  2404.             err = FSpDirCreate(&newFolderSpec, smSystemScript, curDirID);
  2405.         else
  2406.             return err;            // some other type of error, whoa!
  2407.     }
  2408.     else
  2409.     {
  2410.         // folder exists, handle it according to preferences
  2411.         if (gpFWXAppData->fwixPrefs & kConflictRename)
  2412.             CreateUniqueFolder(folderName, &newFolderSpec, curDirID);
  2413.         else if (gpFWXAppData->fwixPrefs & kConflictOverwrite)
  2414.         {
  2415.             err = DeleteDirectory(&newFolderSpec);
  2416.             if (err == noErr)
  2417.             err = FSpDirCreate(&newFolderSpec, smSystemScript, curDirID);
  2418.         }
  2419.         else
  2420.             return kItemExistsError;
  2421.     }
  2422.  
  2423.     return err;
  2424. }
  2425.  
  2426. //////////////////////////////////////////////////////////////////////////////
  2427. //
  2428. //    DeleteDirectory
  2429. //
  2430. //    Delete a directory by removing all of its contents and then it.
  2431. //
  2432. static OSErr DeleteDirectory (
  2433.     FSSpecPtr            pFolderSpec)
  2434. {
  2435.     CInfoPBRec            catInfoPB;
  2436.     OSErr                err;    
  2437.  
  2438.     gCatInfoPB.dirInfo.ioVRefNum = pFolderSpec->vRefNum;
  2439.     FSpGetCatInfo(pFolderSpec, &catInfoPB);
  2440.     err = DeleteDirectoryContents(catInfoPB.dirInfo.ioDrDirID);
  2441.     if (err == noErr)
  2442.         err = FSpDelete(pFolderSpec);
  2443.     
  2444.     return err;
  2445. }
  2446.  
  2447. //////////////////////////////////////////////////////////////////////////////
  2448. //
  2449. //    DeleteDirectoryContents
  2450. //
  2451. //    Delete a directory's contents by deleting each item in the folder.
  2452. //
  2453. static OSErr DeleteDirectoryContents(
  2454.     SInt32                dirID)
  2455. {
  2456.     Str32                fName;
  2457.     UInt32                savedDir;
  2458.     OSErr                err;
  2459.     Boolean                isFolder;
  2460.  
  2461.     do {
  2462.         gCatInfoPB.dirInfo.ioDrDirID = dirID;
  2463.         gCatInfoPB.dirInfo.ioFDirIndex = 1;
  2464.         gCatInfoPB.dirInfo.ioNamePtr = fName;
  2465.         err = PBGetCatInfoSync(&gCatInfoPB);
  2466.         if (err == noErr)
  2467.         {
  2468.             savedDir = dirID;
  2469.             isFolder = gCatInfoPB.dirInfo.ioFlAttrib & ioDirMask;
  2470.             if (isFolder)
  2471.             {
  2472.                 savedDir = gCatInfoPB.dirInfo.ioDrDirID;
  2473.                 err = DeleteDirectoryContents(gCatInfoPB.dirInfo.ioDrDirID);
  2474.                 gCatInfoPB.dirInfo.ioNamePtr = nil;
  2475.             }
  2476.             if (err == noErr)
  2477.             {
  2478.                 gCatInfoPB.dirInfo.ioDrDirID = savedDir;
  2479.                 err = PBHDeleteSync((HParmBlkPtr) &gCatInfoPB);
  2480.             }
  2481.         }
  2482.     } while (err == noErr);
  2483.  
  2484.     if (err == fnfErr)
  2485.         err = noErr;
  2486.  
  2487.     return err;
  2488. }
  2489.  
  2490.  
  2491. //////////////////////////////////////////////////////////////////////////////
  2492. //
  2493. //    DeleteFile
  2494. //
  2495. //    DeleteFile is called by the DeleteDirecotry to remove a single file.
  2496. //
  2497. static OSErr DeleteFile(
  2498.     SInt16                vRefNum,
  2499.     SInt32                dirID,
  2500.     StringPtr            fName)
  2501. {
  2502.     HParamBlockRec pBlock;
  2503.     OSErr err;
  2504.     
  2505.     pBlock.ioParam.ioVRefNum = vRefNum;
  2506.     pBlock.ioParam.ioNamePtr = fName;
  2507.     pBlock.fileParam.ioDirID = dirID;
  2508.     
  2509.     err = PBHDelete(&pBlock,false);
  2510.     
  2511.     return err;
  2512. }
  2513.  
  2514. //////////////////////////////////////////////////////////////////////////////
  2515. //
  2516. //    CreateUniqueFolder
  2517. //
  2518. //    Add a suffix to the folder to make it unique.
  2519. //    Return the new directory id for receives.
  2520. //
  2521. static OSErr CreateUniqueFolder(
  2522.     ConstStr255Param        folderName,
  2523.     FSSpecPtr                pFolderSpec,
  2524.     SInt32                    *dirID)
  2525. {
  2526.     Str32                    newName;        // not sure how big our name buffer is
  2527.                                             // so copy it to a new one
  2528.     UInt32                    nameIndex;
  2529.     UInt8                    nameSuffix[4];
  2530.     UInt8                    endX;
  2531.     OSErr                    err = noErr;
  2532.     
  2533.     endX = folderName[0] + 1;
  2534.     if (endX > 27)        // can only have 31 characters, leave some padding
  2535.         endX = 27;
  2536.     BlockMove(folderName, newName, endX);
  2537.     newName[endX] = '-';
  2538.     endX++;
  2539.     nameIndex = 1;
  2540.     do {
  2541.         NumToString(nameIndex, nameSuffix);
  2542.         BlockMove(nameSuffix + 1, newName + endX, nameSuffix[0]);
  2543.         newName[0] = endX + nameSuffix[0] - 1;
  2544.         err = FSMakeFSSpec (gpFWXAppData->fwixReceiveFolder.vRefNum,
  2545.                             *dirID,
  2546.                             newName,
  2547.                             pFolderSpec);
  2548.         nameIndex++;
  2549.     } while (err == noErr);
  2550.     if (err == fnfErr)
  2551.         err = FSpDirCreate(pFolderSpec, smSystemScript, dirID);
  2552.     return err;
  2553. }
  2554.  
  2555. //////////////////////////////////////////////////////////////////////////////
  2556. //
  2557. //    HandleStartFile
  2558. //
  2559. //    Create a file system spec for the current file record. Create the file.
  2560. //
  2561.  
  2562. static OSErr HandleStartFile(
  2563.     ConstStr255Param        fileName,
  2564.     CurFileInfoPtr            pCurFileInfo)
  2565. {
  2566.     OSErr                    err = noErr;
  2567.     
  2568.     // JKL *** need to handle the user trashing the drop folder
  2569.     err = FSMakeFSSpec (gpFWXAppData->fwixReceiveFolder.vRefNum,
  2570.                         pCurFileInfo->curDirID,
  2571.                         fileName,
  2572.                         pCurFileInfo->pCurFileSpec);
  2573.     if (err != noErr)
  2574.     {
  2575.         if (err == fnfErr)        // should get fnfErr for new file    
  2576.             err = FSpCreate(pCurFileInfo->pCurFileSpec, 0, 0, smSystemScript);
  2577.         else
  2578.             return err;            // some other type of error, whoa!
  2579.     }
  2580.     else
  2581.     {
  2582.         // file exists, handle it according to preferences
  2583.         if (gpFWXAppData->fwixPrefs & kConflictRename)
  2584.         {
  2585.             err = CreateUniqueFile(fileName, pCurFileInfo->pCurFileSpec, pCurFileInfo->curDirID);
  2586.         }
  2587.         else if (gpFWXAppData->fwixPrefs & kConflictOverwrite)
  2588.         {
  2589.             // delete the file and create a new one
  2590.             err = FSpDelete (pCurFileInfo->pCurFileSpec);
  2591.             if (err == noErr)
  2592.             err = FSpCreate (pCurFileInfo->pCurFileSpec, 0, 0, smSystemScript);
  2593.         } else
  2594.             err = kItemExistsError;
  2595.     }    
  2596.     return err;
  2597. }
  2598.  
  2599. //////////////////////////////////////////////////////////////////////////////
  2600. //
  2601. //    CreateUniqueFile
  2602. //
  2603. //    Add a suffix to the filename to make it unique
  2604. //
  2605. static OSErr CreateUniqueFile(
  2606.     ConstStr255Param        fileName,
  2607.     FSSpecPtr                pFileSpec,
  2608.     SInt32                    dirID)
  2609. {
  2610.     Str32                    newName;        // not sure how big our fileName buffer is
  2611.                                             // so copy it to a new one
  2612.     UInt32                    nameIndex;
  2613.     UInt8                    nameSuffix[4];
  2614.     UInt8                    endX;
  2615.     OSErr                    err = noErr;
  2616.     
  2617.     endX = fileName[0] + 1;
  2618.     if (endX > 27)        // can only have 31 characters, leave some padding
  2619.         endX = 27;
  2620.     BlockMove(fileName, newName, endX);
  2621.     newName[endX] = '-';
  2622.     endX++;
  2623.     nameIndex = 1;
  2624.     do {
  2625.         NumToString(nameIndex, nameSuffix);
  2626.         BlockMove(nameSuffix + 1, newName + endX, nameSuffix[0]);
  2627.         newName[0] = endX + nameSuffix[0] - 1;
  2628.         err = FSMakeFSSpec (gpFWXAppData->fwixReceiveFolder.vRefNum,
  2629.                             dirID,
  2630.                             newName,
  2631.                             pFileSpec);
  2632.         nameIndex++;
  2633.     } while (err == noErr);
  2634.     if (err == fnfErr)
  2635.         err = FSpCreate(pFileSpec, 0, 0, smSystemScript);
  2636.     return err;
  2637. }
  2638.  
  2639. //////////////////////////////////////////////////////////////////////////////
  2640. //
  2641. //    HandleStartFork
  2642. //
  2643. //    Open and pre-allocate file fork
  2644. //
  2645. static OSErr HandleStartFork(
  2646.     IOParamPtr                pb,
  2647.     UInt32                    forkLength,
  2648.     SInt16                    refNum)
  2649. {
  2650.     OSErr                    err = noErr;
  2651.  
  2652.     if (err == noErr)
  2653.     {
  2654.         pb->ioRefNum = refNum;
  2655.         pb->ioMisc = (Ptr) forkLength;
  2656.         err = PBSetEOFSync((ParmBlkPtr) pb);
  2657.         if (err != noErr)
  2658.             return err;
  2659.     
  2660.         // reset fork mark to start of file
  2661.         pb->ioPosMode = fsFromStart;
  2662.         pb->ioPosOffset = 0;
  2663.         err = PBSetFPosSync((ParmBlkPtr) pb);
  2664.         if (err != noErr)
  2665.             return err;
  2666.     }
  2667.                 
  2668.     return err;
  2669. }
  2670.  
  2671. //////////////////////////////////////////////////////////////////////////////
  2672. //
  2673. //    HandleForkData
  2674. //
  2675. //    Writes data to the file using an existing parameter block. If the existing parameter
  2676. //    block is full, a new one is created.
  2677. //    
  2678. //
  2679. static OSErr HandleForkData(
  2680.     IOParamPtr                pb,
  2681.     SInt16                    refNum)
  2682. {
  2683.     OSErr                    err = noErr;
  2684.     
  2685.     pb->ioRefNum = refNum;
  2686.     pb->ioPosMode = fsAtMark + 0x0020;
  2687.     pb->ioReqCount = pb->ioActCount;
  2688.     pb->ioActCount = 0;
  2689.     pb->ioCompletion = gpFWXAppData->fileWriteCompletionHandler;
  2690.  
  2691.     err = PBWriteAsync((ParmBlkPtr) pb);
  2692.     
  2693.     return err;    
  2694. }
  2695.     
  2696. //////////////////////////////////////////////////////////////////////////////
  2697. //
  2698. //    HandleFileWriteComplete
  2699. //
  2700. //    Completion routine for PBWrite to file.
  2701. //    Issue a read to the FireWire driver with the parameter block.
  2702. //
  2703. pascal OSErr HandleFileWriteComplete(
  2704.     ParmBlkPtr            pFilePB)
  2705. {
  2706.     OSErr                err;
  2707.     
  2708.     if (pFilePB->ioParam.ioResult != noErr) {
  2709.         sprintf(debugStr, "Error in write to file: %hd", pFilePB->ioParam.ioResult);
  2710.         FWDebugStr((ConstStr255Param) c2pstr (debugStr));
  2711.     }
  2712.  
  2713.     pFilePB->ioParam.ioTrap = kFWXRead;
  2714.     pFilePB->ioParam.ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  2715.     pFilePB->ioParam.ioReqCount = kFWReadDataBufSize;
  2716.     pFilePB->ioParam.ioMisc = (Ptr) kForkData;
  2717.         
  2718.     err = CallFWXNode((IOParamPtr) pFilePB);
  2719.     if (err != noErr) {
  2720.         sprintf(debugStr, "Error in CallFWXNode, FileWriteComplete: %d", err);
  2721.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  2722.     }
  2723.  
  2724.     return (noErr);
  2725. }
  2726.  
  2727. //////////////////////////////////////////////////////////////////////////////
  2728. //
  2729. //    HandleFolderInfo
  2730. //
  2731. //    Writes the finder catalog info for the folder
  2732. //
  2733. static OSErr HandleFolderInfo(
  2734.     CInfoPBPtr            pCatInfoPB,
  2735.     SInt32                dirID)
  2736. {
  2737.     OSErr                err;                            
  2738.     
  2739.     pCatInfoPB->dirInfo.ioFDirIndex = 0;        // use ioDirID
  2740.     pCatInfoPB->dirInfo.ioVRefNum = gpFWXAppData->fwixReceiveFolder.vRefNum;
  2741.     pCatInfoPB->dirInfo.ioDrDirID = dirID;
  2742.     pCatInfoPB->dirInfo.ioNamePtr = nil;
  2743.     
  2744.     err = PBSetCatInfoSync(pCatInfoPB);
  2745.     
  2746.     return err;
  2747. }
  2748.  
  2749. //////////////////////////////////////////////////////////////////////////////
  2750. //
  2751. //    HandleFileInfo
  2752. //
  2753. //    Writes the finder info for the file
  2754. //
  2755. static OSErr HandleFileInfo(
  2756.     FSSpecPtr            pNewFileSpec,
  2757.     CInfoPBPtr            pCatInfoPB)
  2758. {
  2759.     OSErr                err;                            
  2760.     
  2761.     pCatInfoPB->hFileInfo.ioFDirIndex = 0;        // use ioNamePtr and ioDirID
  2762.     pCatInfoPB->hFileInfo.ioVRefNum = pNewFileSpec->vRefNum;
  2763.     pCatInfoPB->hFileInfo.ioDirID = pNewFileSpec->parID;
  2764.     pCatInfoPB->hFileInfo.ioNamePtr = pNewFileSpec->name;
  2765.     
  2766.     // don't copy the hasBeenInited bit */
  2767.     pCatInfoPB->hFileInfo.ioFlFndrInfo.fdFlags =
  2768.             pCatInfoPB->hFileInfo.ioFlFndrInfo.fdFlags & 0xfeff;
  2769.     
  2770.     err = PBSetCatInfoSync(pCatInfoPB);
  2771.     
  2772.     /****
  2773.      * Some idea of how to take care of file lock
  2774.      * what about comments? custom icons? JKL****
  2775.      *
  2776.     if ((err == noErr) && (copyLockBit) && (pCatInfoPB->hFileInfo.ioFlAttrib & 0x01) != 0))
  2777.     {
  2778.         pb.hPB.fileParam.ioFVersNum = 0;
  2779.         error = PBHSetFLockSync(&pb.hPB);
  2780.         if ( (error != noErr) && (objectIsDirectory) )
  2781.             error = noErr; // ignore lock errors if destination is directory
  2782.     }
  2783.      *
  2784.     ****/
  2785.     return err;
  2786. }
  2787.  
  2788. //////////////////////////////////////////////////////////////////////////////
  2789. //
  2790. //    CleanupCopyDialog
  2791. //
  2792. //    Destroys the copy dialog
  2793. //
  2794. void CleanupCopyDialog(
  2795.     WindowPtr            theDialog)
  2796. {
  2797.     Handle                item;
  2798.     Rect                box;
  2799.     SInt16                itemType;
  2800.  
  2801.     GetDialogItem(theDialog, kProgressBarUserItem, &itemType, &item, &box);
  2802.     DisposeRoutineDescriptor((UserItemUPP) item);
  2803.     DisposeDialog(theDialog);
  2804.     EnableItem(GetMenuHandle(kFileMenuID), 0);
  2805.     EnableItem(GetMenuHandle(kEditMenuID), 0);
  2806.     EnableItem(GetMenuHandle(kViewMenuID), 0);
  2807.     DrawMenuBar();
  2808.     gBytesToCopy = 0;
  2809.     gItemsToCopy = 0;
  2810. }
  2811.  
  2812. //////////////////////////////////////////////////////////////////////////////
  2813. //
  2814. //    DisplayCopyDialog
  2815. //
  2816. //    Creates the copy dialog
  2817. //
  2818. static OSErr DisplayCopyDialog (void)
  2819. {
  2820.     DialogPtr            pDialog;
  2821.     UserItemUPP            pUserDrawProc;
  2822.     Handle                item;
  2823.     Rect                box;
  2824.     SInt16                itemType;
  2825.     OSErr                err = noErr;
  2826.     
  2827.     pUserDrawProc = NewUserItemProc(DrawProgressBar);
  2828.     if (pUserDrawProc == nil)
  2829.         return memFullErr;
  2830.         
  2831.     pDialog = GetNewDialog(kCopyProgressDlog, nil, (WindowPtr) -1);
  2832.     if (pDialog != nil) {
  2833.         // get handle to progress bar user item and replace with draw proc
  2834.         GetDialogItem(pDialog, kProgressBarUserItem, &itemType, &item, &box);
  2835.         SetDialogItem(pDialog, kProgressBarUserItem, itemType,
  2836.                         (Handle) pUserDrawProc, &box);
  2837.         ShowWindow(pDialog);
  2838.     } else
  2839.         err = ResError();
  2840.     
  2841.     DisableItem(GetMenuHandle(kFileMenuID), 0);
  2842.     DisableItem(GetMenuHandle(kEditMenuID), 0);
  2843.     DisableItem(GetMenuHandle(kViewMenuID), 0);
  2844.     DrawMenuBar();
  2845.     return err;
  2846. }
  2847.  
  2848. //////////////////////////////////////////////////////////////////////////////
  2849. //
  2850. //    DrawProgressBar
  2851. //
  2852. //    Draws progress bar in copy dialog
  2853. //
  2854. pascal void DrawProgressBar(
  2855.     WindowPtr        theWindow,
  2856.     SInt16            itemNo)
  2857. {
  2858.     WindowPtr        curPort;
  2859.     Handle            item;
  2860.     Rect            box;
  2861.     RGBColor        curColor;
  2862.     RGBColor        paintColor;
  2863.     unsigned char    s[8];
  2864.     float            rightVal;
  2865.     SInt16            itemType;
  2866.     
  2867.     GetDialogItem(theWindow, itemNo, &itemType, &item, &box);
  2868.     GetPort(&curPort);
  2869.     SetPort(theWindow);
  2870.     
  2871.     FrameRect(&box);
  2872.     
  2873.     InsetRect(&box, 1, 1);
  2874.     GetForeColor(&curColor);
  2875.     paintColor.red = 40000;
  2876.     paintColor.blue = 45000;
  2877.     paintColor.green = 40000;
  2878.     RGBForeColor(&paintColor);
  2879.     PaintRect(&box);
  2880.  
  2881.     rightVal = (float) gBytesCopied / (float) gBytesToCopy;
  2882.     box.right = rightVal * 200.0 + box.left;
  2883.     paintColor.red = 10000;
  2884.     paintColor.blue = 15000;
  2885.     paintColor.green = 10000;
  2886.     RGBForeColor(&paintColor);
  2887.     PaintRect(&box);
  2888.     
  2889.     RGBForeColor(&curColor);
  2890.  
  2891.     MoveTo(167, 22);
  2892.     NumToString(gItemsToCopy, s);
  2893.     DrawString((ConstStr255Param) s);
  2894.  
  2895.     if (gSendQHdr.qHead != nil)
  2896.     {
  2897.         MoveTo(94, 47);
  2898.         DrawString(((TxFSSpecPtr) gSendQHdr.qHead)->pFSSpec->name);
  2899.     }
  2900.  
  2901.     SetPort(curPort);
  2902. }
  2903.  
  2904. //////////////////////////////////////////////////////////////////////////////
  2905. //
  2906. //    UpdateProgressBar
  2907. //
  2908. //    Advances progress bar to show copy status
  2909. //
  2910. void UpdateProgressBar (
  2911.     WindowPtr        theWindow,
  2912.     SInt16            itemNo)
  2913. {
  2914.     WindowPtr        curPort;
  2915.     Handle            item;
  2916.     Rect            box;
  2917.     RGBColor        curColor;
  2918.     RGBColor        paintColor;
  2919.     static UInt32    lastCopyCount = 0;
  2920.     unsigned char    s[8];
  2921.     float            rightVal;
  2922.     SInt16            itemType;
  2923.     
  2924.     GetDialogItem(theWindow, itemNo, &itemType, &item, &box);
  2925.     GetPort(&curPort);
  2926.     SetPort(theWindow);
  2927.     
  2928.     InsetRect(&box, 1, 1);
  2929.     GetForeColor(&curColor);
  2930.  
  2931.     rightVal = (float) gBytesCopied / (float) gBytesToCopy;
  2932.     box.right = rightVal * 200.0 + box.left;
  2933.     paintColor.red = 10000;
  2934.     paintColor.blue = 15000;
  2935.     paintColor.green = 10000;
  2936.     RGBForeColor(&paintColor);
  2937.     PaintRect(&box);
  2938.     
  2939.     RGBForeColor(&curColor);
  2940.  
  2941.     if (lastCopyCount != gItemsToCopy) {
  2942.         SetRect(&box, 166, 10, 320, 27);
  2943.         EraseRect(&box);
  2944.         MoveTo(167, 22);
  2945.         NumToString(gItemsToCopy, s);
  2946.         DrawString((ConstStr255Param) s);
  2947.     
  2948.         SetRect(&box, 93, 35, 320, 52);
  2949.         EraseRect(&box);
  2950.         MoveTo(94, 47);
  2951.         DrawString(((TxFSSpecPtr) gSendQHdr.qHead)->pFSSpec->name);
  2952.         
  2953.         lastCopyCount = gItemsToCopy;
  2954.     }
  2955.  
  2956.     SetPort(curPort);
  2957. }
  2958.  
  2959. //////////////////////////////////////////////////////////////////////////////
  2960. //
  2961. //    FSpGetCatInfo
  2962. //
  2963. //    Utility routine to call PBGetCatInfo using file system spec
  2964. //
  2965.  
  2966. OSErr FSpGetCatInfo(
  2967.     FSSpec             *pFSSpec,
  2968.     CInfoPBPtr        pCatInfoPB)
  2969. {
  2970.     pCatInfoPB->hFileInfo.ioFDirIndex = 0;
  2971.     pCatInfoPB->hFileInfo.ioDirID = pFSSpec->parID;
  2972.     pCatInfoPB->hFileInfo.ioVRefNum = pFSSpec->vRefNum;
  2973.     pCatInfoPB->hFileInfo.ioNamePtr = pFSSpec->name;
  2974.     
  2975.     return PBGetCatInfoSync(pCatInfoPB);
  2976. }
  2977.  
  2978. //////////////////////////////////////////////////////////////////////////////
  2979. //
  2980. //    GetItemSize
  2981. //
  2982. //    Calculate size of item.
  2983. //
  2984. OSErr GetItemSize(
  2985.     NodeSendItemPtr        pSendItem)
  2986. {
  2987.     CInfoPBRec        catInfo;
  2988.     UInt32                itemCount;
  2989.     OSErr            err;
  2990.     Boolean            isFile;
  2991.     
  2992.     pSendItem->itemSize = 0;
  2993.     itemCount = 0;
  2994.     err = FSpGetCatInfo(&pSendItem->sendItemSpec, &catInfo);
  2995.  
  2996.     itemCount++;
  2997.     isFile = !(catInfo.dirInfo.ioFlAttrib & ioDirMask);
  2998.     if (isFile)
  2999.     {
  3000.         pSendItem->itemSize += catInfo.hFileInfo.ioFlLgLen;
  3001.         pSendItem->itemSize += catInfo.hFileInfo.ioFlRLgLen;
  3002.     }
  3003.     else
  3004.     {
  3005.         err = CalcDirectorySize (catInfo.dirInfo.ioDrDirID,
  3006.                                  pSendItem->sendItemSpec.vRefNum,
  3007.                                  &pSendItem->itemSize,
  3008.                                  &itemCount);
  3009.     }
  3010.     return err;
  3011. }
  3012.  
  3013. //////////////////////////////////////////////////////////////////////////////
  3014. //
  3015. //    CountCopyData
  3016. //
  3017. //    Tally items to be copied.
  3018. //
  3019. OSErr CountCopyData(
  3020.     FSSpec             *pFSSpec)
  3021. {
  3022.     CInfoPBRec        catInfo;
  3023.     OSErr            err;
  3024.     Boolean            isFile;
  3025.     
  3026.     err = FSpGetCatInfo(pFSSpec, &catInfo);
  3027.     if (err == noErr)
  3028.     {
  3029.         gItemsToCopy++;
  3030.         isFile = !(catInfo.dirInfo.ioFlAttrib & ioDirMask);
  3031.         if (isFile)
  3032.         {
  3033.                 gBytesToCopy += catInfo.hFileInfo.ioFlLgLen;
  3034.                 gBytesToCopy += catInfo.hFileInfo.ioFlRLgLen;
  3035.         }
  3036.         else
  3037.         {
  3038.             err = CalcDirectorySize (catInfo.dirInfo.ioDrDirID,
  3039.                                      pFSSpec->vRefNum,
  3040.                                      &gBytesToCopy,
  3041.                                      &gItemsToCopy);
  3042.         }
  3043.     }
  3044.     return err;
  3045. }    
  3046.  
  3047. //////////////////////////////////////////////////////////////////////////////
  3048. //
  3049. //    CalcDirectorySize
  3050. //
  3051. //    Traverse a directory finding each of its items. If an item in a directory
  3052. //    is also a directory, recurse to find all of its items. It an item is a
  3053. //    file add its size to the byte count.
  3054. //
  3055.  
  3056. static OSErr CalcDirectorySize (
  3057.     SInt32                dirID,
  3058.     SInt16                vRefNum,
  3059.     UInt32                *dirSize,
  3060.     UInt32                *dirItems)
  3061. {
  3062.     SInt16                index;
  3063.     OSErr                err = noErr;
  3064.     Boolean                isFile;
  3065.     
  3066.     gCatInfoPB.hFileInfo.ioVRefNum = vRefNum;
  3067.         
  3068.     for (index = 1; ; index++)
  3069.     {
  3070.         // reset the directory id after each call to PBGetCatInfo
  3071.         gCatInfoPB.hFileInfo.ioDirID = dirID;
  3072.         gCatInfoPB.hFileInfo.ioFDirIndex = index;
  3073.         
  3074.         err = PBGetCatInfoSync(&gCatInfoPB);
  3075.         if (err != noErr)
  3076.         {
  3077.             // returns file not found when directory has been traversed
  3078.             if (err == fnfErr)
  3079.                 err = noErr;
  3080.             break;
  3081.         }
  3082.         *dirItems = *dirItems + 1;
  3083.         isFile = !(gCatInfoPB.dirInfo.ioFlAttrib & ioDirMask);
  3084.         if (isFile)
  3085.         {
  3086.             *dirSize += gCatInfoPB.hFileInfo.ioFlLgLen;
  3087.             *dirSize += gCatInfoPB.hFileInfo.ioFlRLgLen;
  3088.         }
  3089.         else
  3090.         {
  3091.             err = CalcDirectorySize (gCatInfoPB.dirInfo.ioDrDirID,
  3092.                                      vRefNum,
  3093.                                      dirSize,
  3094.                                      dirItems);
  3095.         }
  3096.     }
  3097.     return err;
  3098.             
  3099. }
  3100.  
  3101. //////////////////////////////////////////////////////////////////////////////
  3102. //
  3103. //    SetupFileReadPB
  3104. //
  3105. //    Zero out unused fields and set used fields
  3106. //
  3107.  
  3108. void SetupFileReadPB(
  3109.     IOParamPtr        pb)
  3110. {
  3111.     pb->ioCompletion = gpFWXAppData->fileReadCompletionHandler;
  3112.     pb->ioRefNum = gCurForkRefNum;
  3113.     pb->ioReqCount = kFileReadBufSize;
  3114.     pb->ioPosMode = fsAtMark + 0x0020;
  3115.  
  3116.     pb->qLink = nil;
  3117.     pb->qType = 0;
  3118.     pb->ioTrap = 0;
  3119.     pb->ioCmdAddr = nil;
  3120.     pb->ioResult = noErr;
  3121.     pb->ioNamePtr = nil;
  3122.     pb->ioVRefNum = 0;
  3123.     pb->ioVersNum = 0;
  3124.     pb->ioPermssn = 0;
  3125.     pb->ioMisc = nil;
  3126.     pb->ioActCount = 0;
  3127.     pb->ioPosOffset = 0;
  3128.     
  3129.     // pb->ioBuffer            // set by init routine
  3130. }
  3131.  
  3132. //////////////////////////////////////////////////////////////////////////////
  3133. //
  3134. //    SetupFWWritePB
  3135. //
  3136. //    Zero out unused fields and set used fields
  3137. //
  3138.  
  3139. void SetupFWWritePB(
  3140.     IOParamPtr        pb)
  3141. {
  3142.     pb->ioCompletion = (IOCompletionUPP) HandleFWWriteComplete;
  3143.     pb->ioNamePtr = (StringPtr) ((TxFSSpecPtr) gSendQHdr.qHead)->recvNode;
  3144.     pb->ioTrap = kFWXWrite;
  3145.  
  3146.     pb->qLink = nil;
  3147.     pb->qType = 0;
  3148.     pb->ioCmdAddr = nil;
  3149.     pb->ioResult = noErr;
  3150.     pb->ioVRefNum = 0;
  3151.     pb->ioVersNum = 0;
  3152.     pb->ioPermssn = 0;
  3153.     pb->ioActCount = 0;
  3154.     pb->ioPosMode = 0;
  3155.     pb->ioPosOffset = 0;
  3156.     
  3157.     // pb->ioMisc            // set by routine doing the write
  3158.     // pb->ioBuffer            // set by init routine
  3159.     // pb->ioReqCount        // set by routine doing the write
  3160. }
  3161.  
  3162.  
  3163. //////////////////////////////////////////////////////////////////////////////
  3164. //
  3165. //    SetupFWControlPB
  3166. //
  3167. //    Zero out unused fields and set used fields
  3168. //
  3169.  
  3170. void SetupFWControlPB(
  3171.     IOParamPtr        pb)
  3172. {
  3173.     pb->ioCompletion = (IOCompletionUPP) HandleFWControlComplete;
  3174.     pb->ioNamePtr = (StringPtr) ((TxFSSpecPtr) gSendQHdr.qHead)->recvNode;
  3175.     pb->ioTrap = kFWXWrite;
  3176.  
  3177.     pb->qLink = nil;
  3178.     pb->qType = 0;
  3179.     pb->ioCmdAddr = nil;
  3180.     pb->ioResult = noErr;
  3181.     pb->ioVRefNum = 0;
  3182.     pb->ioVersNum = 0;
  3183.     pb->ioPermssn = 0;
  3184.     pb->ioActCount = 0;
  3185.     pb->ioPosMode = 0;
  3186.     pb->ioPosOffset = 0;
  3187.     
  3188.     // pb->ioMisc            // set by routine doing the write
  3189.     // pb->ioBuffer            // set by init routine
  3190.     // pb->ioReqCount        // set by routine doing the write
  3191. }
  3192.  
  3193.  
  3194. //////////////////////////////////////////////////////////////////////////////
  3195. //
  3196. //    FWIXDequeue
  3197. //
  3198. //    Reentrant safe dequeue.
  3199. //
  3200.  
  3201. OSErr FWIXDequeue(
  3202.     QElemPtr            *ppQElem,
  3203.     QHdrPtr                pQHdr)
  3204. {
  3205.     QElemPtr    pQElem;
  3206.     OSErr        err = noErr;
  3207.  
  3208.     // Attempt to dequeue element at head of queue.
  3209.     pQElem = pQHdr->qHead;
  3210.     if (pQElem != nil)
  3211.         err = Dequeue (pQElem, pQHdr);
  3212.  
  3213.     // If we failed, try again until we get an element or none are left
  3214.     // in queue.
  3215.     while ((pQElem != nil) && (err != noErr))
  3216.     {
  3217.         pQElem = pQHdr->qHead;
  3218.         if (pQElem != nil)
  3219.             err = Dequeue (pQElem, pQHdr);
  3220.     }
  3221.     
  3222.     // Return results.
  3223.     if (err == noErr)
  3224.         *ppQElem = pQElem;
  3225.     else
  3226.         *ppQElem = nil;
  3227.     
  3228.     return (err);
  3229. }